1. 程式人生 > 實用技巧 >leetcode hot 100-2. 兩數相加

leetcode hot 100-2. 兩數相加

2. 兩數相加

給出兩個非空 的連結串列用來表示兩個非負的整數。其中,它們各自的位數是按照逆序的方式儲存的,並且它們的每個節點只能儲存一位數字。

如果,我們將這兩個數相加起來,則會返回一個新的連結串列來表示它們的和。

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

示例:

輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807

思路一:模擬大數加法

模擬大數加法,先處理都不為空的結點,然後分別處理另一個更長的連結串列中剩下的結點,最後還要考慮fn的值是否需要再建立一個結點。

 1
class Solution { 2 public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 3 // 模擬大數加法 4 ListNode head = new ListNode(); // 增加一個冗餘的頭結點 5 ListNode cur = head; 6 7 int fn = 0; // 表示進位 8 int temp = 0; // 表示兩個個位數相加的臨時結果 9 ListNode p1 = l1, p2 = l2;
10 while(p1 != null && p2 != null){ 11 temp = p1.val + p2.val + fn; 12 cur.next = new ListNode(temp % 10); // 只儲存餘數 13 fn = temp / 10; // 更新進位 14 cur = cur.next; 15 p1 = p1.next; 16 p2 = p2.next; 17 } 18 //
處理p1多餘的結點 19 while(p1 != null){ 20 temp = p1.val + fn; 21 cur.next = new ListNode(temp % 10); // 只儲存餘數 22 fn = temp / 10; // 更新進位 23 cur = cur.next; 24 p1 = p1.next; 25 } 26 // 處理p2多餘的結點 27 while(p2 != null){ 28 temp = p2.val + fn; 29 cur.next = new ListNode(temp % 10); // 只儲存餘數 30 fn = temp / 10; // 更新進位 31 cur = cur.next; 32 p2 = p2.next; 33 } 34 35 if(fn != 0){ // 處理最後的進位 36 cur.next = new ListNode(fn); // 只儲存餘數 37 } 38 return head.next; 39 } 40 }

leetcode執行用時:2 ms > 99.92%, 記憶體消耗:39 MB > 46.86%

複雜度分析:

時間複雜度:O(max(n1, n2))。n1和 n2 分別為連結串列的長度,雖然程式碼實現中有3個迴圈,但是通過實現邏輯可以看出所有迭代次數之和剛好是兩個連結串列長度大的那條的結點個數,即max(n1, n2)。

空間複雜度:O(max(n1, n2))。這是用來儲存結果的連結串列的長度,如果不考慮這部分空間複雜度,則空間複雜度為O(1)。

思路二:思路一的改進版

思路和思路一一樣,同樣是利用了大數加法的思想,但是可以看出思路一的程式碼太長,存在冗餘程式碼,所以考慮將三個迴圈放在同一個迴圈中。思路一之所以要分成3個迴圈,是因為擔心其中一個連結串列的長度大於另一個連結串列長度,這樣遍歷到短連結串列的結尾時長連結串列還沒有遍歷完,如果繼續遍歷則會導致短連結串列空指標異常。所以改進就是取值之前先判斷結點是否為空,如果為空,則用0代替,因為0不會改變結果。當然指標後移的時候也要判斷結點是否為空,如果不為空才能後移。

 1 class Solution {
 2     public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
 3         // 模擬大數加法
 4         ListNode head = new ListNode(); // 增加一個冗餘的頭結點
 5         ListNode cur = head;
 6 
 7         int fn = 0;     // 表示進位
 8         int temp = 0;   // 表示兩個個位數相加的臨時結果
 9         ListNode p1 = l1, p2 = l2;
10         while(p1 != null || p2 != null){
11             int x = (p1 != null ? p1.val : 0);  // 取值之前先判斷結點是否為空
12             int y = (p2 != null ? p2.val : 0);
13             temp = x + y + fn;
14             cur.next = new ListNode(temp % 10);  // 只儲存餘數
15             fn = temp / 10; // 更新進位
16             cur = cur.next;
17             if(p1 != null){     // 後移之前也需判斷結點是否為空
18                 p1 = p1.next;
19             }
20             if(p2 != null){
21                 p2 = p2.next;
22             }
23         }
24 
25         if(fn != 0){ // 處理最後的進位
26             cur.next = new ListNode(fn);  // 只儲存餘數
27         }
28         return head.next;
29     }
30 }
leetcode 執行用時:2 ms > 99.92%, 記憶體消耗:38.8 MB > 75.26%

複雜度分析:

時間複雜度:O(max(n1, n2))。n1和 n2 分別為連結串列的長度,可以看出所有迭代次數之和剛好是兩個連結串列長度大的那條的結點個數,即max(n1, n2)。

空間複雜度:O(max(n1, n2))。這是用來儲存結果的連結串列的長度,如果不考慮這部分空間複雜度,則空間複雜度為O(1)。