兩數相加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)