- 題目:2. 兩數相加
- 難度:中等
- 分類:鏈表
- 解決方案:鏈表的遍歷
題目描述
給出兩個非空的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照逆序的方式存儲的,并且它們的每個節點只能存儲一位數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
注意:您可以假設除了數字0之外,這兩個數都不會以0開頭。
示例:
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807
分析
這個題理解起來難度不大,就是將數字從個位數開始將數字放到鏈表的各個結點上,如下所示:
鏈表表示數字.png
然后兩個鏈表的對應位置上的數字相加,將相加的值保存到結果鏈表中。這里需要注意兩個關鍵點:一是如果兩個值相加大于9該怎么辦?二是兩個鏈表長度不一致該怎么辦?
對于關鍵點一:我們需要借助一個進位標識carry
,當兩數之和大于9時將carry
標識為1,否則標識為0。
對于關鍵點二:我們以最長鏈表作為終點,對于較短鏈表對應位置的數值,我們用0來補齊。
下面分析一個具體實例,該實例包含上述兩個關鍵點,如下圖所示:
兩數相加.png
如上圖所示,數字342的鏈表較短,數字7465的鏈表較長。當兩個數字的第二個結點相加時,它們的和為10,這時就需要進位,即carry=1
,且將個位數保留作為結果鏈表的值。當較短的鏈表指向為null
結點時,較長的鏈表指向的值為7,這需要將較短鏈表的值設置為0,即結果為0+7。
通過上面分析后,再看看如下java
便一目了然。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
// 創建結果鏈表的頭節點,默認該節點中的value為-1
ListNode dummy = new ListNode(-1);
ListNode pre = dummy;
// 進位標識carry,默認為0
int carry = 0;
// 遍歷鏈表,當兩個鏈表都為空時,退出
while(l1 != null || l2 != null){
// 判斷該節點是否為空,當結點為空時,用0補齊;不為空時,加數即為節點的值
int d1 = (l1 == null) ? 0 : l1.val;
int d2 = (l2 == null) ? 0 : l2.val;
// 對結點求和,注意:求和是需要考慮到進位
int sum = d1 + d2 + carry;
// 更新進位標識
carry = (sum >= 10) ? 1 : 0;
// sum%10標識求和的個位數,將其保存到結果鏈表中
pre.next = new ListNode(sum % 10);
pre = pre.next;
if(l1 != null) l1 = l1.next;
if(l2 != null) l2 = l2.next;
}
// 重點,這是一個特殊情況,當兩個鏈表計算完后,
// 還需要判斷進位標識是否為1,如果為1,如23+81=104,需要創建一個結點保存最高位
if(carry == 1)
pre.next = new ListNode(1);
return dummy.next;
}
}
兩數相加計算結果.png
對于時間復雜度和空間復雜度,該題都為O(n)。
Github地址
參考鏈接
更多文章,請掃描二維碼關注『算法半島』