兩數相加ii(add-two-numbers-ii)

兩數相加ii(add-two-numbers-ii)

給定兩個非空鏈表來代表兩個非負整數。數字最高位位於鏈表開始位置。它們的每個節點只存儲單個數字。將這兩數相加會返回一個新的鏈表。

你可以假設除了數字 0 之外,這兩個數字都不會以零開頭。

進階:

如果輸入鏈表不能修改該如何處理?換句話說,你不能對列表中的節點進行翻轉。

示例:

輸入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出: 7 -> 8 -> 0 -> 7

雙棧+單鏈表插入法

雙棧+單鏈表插入

解題思路

兩數相加不一樣,這裏(兩數相加ii)的鏈表是高位在前。兩鏈表的長度不一樣,無法直接相加。所以,我們可以把鏈表轉爲棧。這裏,從棧中彈出來的就是低位相加了。
相加過程還需要考慮進位的情況,每次從棧中彈出來的兩數相加,需要分離出進位個位,其中,個位生成新的節點,進位待下一次使用。
這裏,我們用了一個啞節點dummy來保存新的鏈表,新生成的節點需要插入到dummy後面,將鏈表向後擠。
最後,如果進位不爲零,我們還需要把進位添加到鏈表中。

代碼

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    	//雙棧
    	Stack<ListNode> s1 = new Stack<ListNode>();
    	Stack<ListNode> s2 = new Stack<ListNode>();
    	ListNode dummy = new ListNode(-1);
        ListNode tmpl1 = l1;
        ListNode tmpl2 = l2;
        ListNode pre = dummy;
        while(tmpl1!=null) {
        	s1.add(tmpl1);
        	tmpl1 = tmpl1.next;
        }
        while(tmpl2!=null) {
        	s2.add(tmpl2);
        	tmpl2 = tmpl2.next;
        }
        int carry = 0;
        while(!s1.isEmpty()&&!s2.isEmpty()) {
        	//雙棧彈出
        	int k = carry+s1.pop().val+s2.pop().val;
        	//獲取進位
        	carry = k/10;
        	//獲取個位
        	int cur = k%10;
        	//生成新節點
        	ListNode node = new ListNode(cur);
        	//單鏈表插入
        	node.next = pre.next;
        	pre.next = node;
        }
        while(!s1.isEmpty()) {
        	int k = carry + s1.pop().val;
        	carry = k/10;
        	int cur = k%10;
        	ListNode node = new ListNode(cur);
        	node.next = pre.next;
        	pre.next = node;
        }
        while(!s2.isEmpty()) {
        	int k = carry + s2.pop().val;
        	carry = k/10;
        	int cur = k%10;
        	ListNode node = new ListNode(cur);
        	node.next = pre.next;
        	pre.next = node;
        }
        if(carry>0) {
        	ListNode node = new ListNode(carry);
        	node.next = pre.next;
        	pre.next = node;
        }
        return dummy.next;
    }
執行用時 :6 ms, 在所有 Java 提交中擊敗了59.04%的用戶
內存消耗 :52.4 MB, 在所有 Java 提交中擊敗了5.05%的用戶

大神寫的簡潔版(雙棧+單鏈表插入)

解題思路

定義兩個Stack<Integer>棧,用來將鏈表反轉。

代碼

    public ListNode addTwoNumbers2(ListNode l1, ListNode l2) {
		Stack<Integer> stack1 = new Stack<Integer>();
		Stack<Integer> stack2 = new Stack<Integer>();

		while (l1 != null) {
			stack1.push(l1.val);
			l1 = l1.next;
		}

		while (l2 != null) {
			stack2.push(l2.val);
			l2 = l2.next;
		}

		int carry = 0;
		ListNode result = null;
		while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {

			int m = stack1.isEmpty() ? 0 : stack1.pop();
			int n = stack2.isEmpty() ? 0 : stack2.pop();

			int sum = m + n + carry;
			carry = sum >= 10 ? 1 : 0;
			sum = sum % 10;

			// 鏈表頭插法 注意前面鏈頭定義爲null
			ListNode temp = new ListNode(sum);
			temp.next = result;
			result = temp;
		}

		return result;
	}

內存消耗有所降低。

執行用時 :7 ms, 在所有 Java 提交中擊敗了56.00%的用戶
內存消耗 :45.8 MB, 在所有 Java 提交中擊敗了8.01%的用戶

遞歸解法

解題思路

採用遞歸解法
在進行遞歸之前我們先遍歷得到l1與l2的長度len1與len2;

遞歸解法:

  • 如果len1長度與len2都爲1,那麼當前的值應爲(l1.val+l2.val)%10,進位更新爲(l1.val+l2.val)/10
  • 如果len1長度大於len2,遞歸計算(l1.next,l2),當前的值應爲(l1.val+進位)%10,進位更新爲(l1.val+進位)/10
  • 如果len1長度等於len2,遞歸計算(l1.next,l2.next),當前的值應爲(l1.val+進位+l2.val)%10,進位更新爲(l1.val+進位+l2.val)/10
    返回當前節點的指針
    遞歸結束

爲方便遞歸,遞歸開始前我們保證len1>=len2,另外遞歸結束後若進位爲1,需要新建值爲1的頭節點
(代碼沒有仔細優化)

代碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    int flow=0;
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if(l1==null) return l2;
        if(l2==null) return l1;
        ListNode res1=l1,res2=l2;
        int len1=0,len2=0;
        while(l1!=null){
            len1++;
            l1=l1.next;
        }
        while(l2!=null){
            len2++;
            l2=l2.next;
        }
        ListNode res=len1>len2?add(res1,res2,len1,len2):add(res2,res1,len2,len1);
        if(flow==1) {
            res1=new ListNode(1);
            res1.next=res;
            return res1;
        }
        return res;
    }
    public ListNode add(ListNode l1, ListNode l2,int len1,int len2) {
        int temp;
        if((len1==1)&&(len2==1)){
            temp=l1.val;
            l1.val=(l1.val+l2.val)%10;
            flow=(temp+l2.val)/10;
            return l1;
        } 
        if(len1>len2) {
            temp=l1.val;
            l1.next=add(l1.next, l2,len1-1,len2);
            l1.val=(temp+flow)%10;
            flow=(temp+flow)/10;
            return l1;
        }
        l1.next=add(l1.next, l2.next,len1-1,len2-1);
        temp=l1.val;
        l1.val=(temp+flow+l2.val)%10;
        flow=(temp+flow+l2.val)/10;
        return l1;

    }
}

測試用例

    public static void main(String[] args) {
		ListNode l1 = new ListNode(7);
		ListNode l2 = new ListNode(2);
		ListNode l3 = new ListNode(4);
		ListNode l4 = new ListNode(3);
		l1.next = l2;
		l2.next = l3;
		l3.next = l4;
		
		ListNode l11 = new ListNode(5);
		ListNode l12 = new ListNode(6);
		ListNode l13 = new ListNode(4);
		l11.next = l12;
		l12.next = l13;
		
		System.out.println(l1);
		System.out.println(l11);
		Solution solu = new Solution();
		System.out.println(solu.addTwoNumbers(l1, l11));
		
		ListNode l_5_1 = new ListNode(5);
		ListNode l_5_2 = new ListNode(5);
		System.out.println(solu.addTwoNumbers(l_5_1, l_5_2));
	}

參考資料

leecode兩數相加ii
兩數相加_詳解
兩數相加(add-two-numbers)
兩數相加ii(add-two-numbers-ii)

發佈了171 篇原創文章 · 獲贊 48 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章