原題地址: https://leetcode-cn.com/problems/add-two-numbers/
題目描述
給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
題目示例:
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 輸出:7 -> 0 -> 8 原因:342 + 465 = 807
[假] JavaScript 輸入
[2,4,3] [5,6,4]
[假] JavaScript 輸出
[7, 0, 8]
真實的 JavaScript 輸入
這里有一個很坑的地方是雖然上面的輸入和輸出是數組,但是並不能按照數組輸入輸出,因為函數上明確寫了,輸入的是 ListNode
類型。
我在做這個的時候就被數組給迷惑了,怎么輸出都是 undefined。
而默認 ListNode
這個數據類型是已經存在的,因此在本地寫代碼的時候,是需要構造 l1
和 l2
兩個數據的,否則我不相信憑空就能寫出題解來。
首先我們已經知道,l1 和 l2 都是 ListNode
類型,因此輸入 [2, 4, 3]
中的 2 / 4 / 3 分別是每個 ListNode 的 val。
因此 l1 可以如下構造:
let l1_1 = new ListNode(2); let l1_2 = new ListNode(4); let l1_3 = new ListNode(3); l1_1.next = l1_2; l1_2.next = l1_3; // l1 = l1_1
同樣的 l2 輸入可以如下構造:
let l2_1 = new ListNode(5); let l2_2 = new ListNode(6); let l2_3 = new ListNode(4); l2_1.next = l2_2; l2_2.next = l2_3; // l2 = l2_1;
因此本地寫代碼調用的時候實際上如下所示:
const input1 = l1_1; const input2 = l2_1; console.log(addTwoNumbers(input1, input2));
真實的 JavaScript 輸出
從注釋上可以發現,最終的輸出也是 ListNode 類型的,因此最終輸出結果應該如下:
ListNode { val: 7, next: ListNode { val: 0, next: ListNode { val: 8, next: null } } }
JavaScript 題解
當理解了 l1 和 l2 都是 ListNode 類型之后,就很好去做這個事情了。
下面代碼很簡單,主要是兩部分:
- 鏈表的便利
- 個位數相加 、 進位
具體的流程已經寫到了注釋上。
/** * @param {ListNode} l1 * @param {ListNode} l2 * @return {ListNode} */ var addTwoNumbers = function(l1, l2) { let resNode = new ListNode(0); // 臨時使用的 node 用來不停的增加鏈表節點 let result = resNode; // 第一次掛載 let tmpS = 0; // 相加 > 10 的進位數(1 或 0) while(l1 || l2 || tmpS) { // 判斷 tmpS 的目的是防止最后還有一位進位需要前置 let val1 = l1 ? l1.val || 0 : 0; // 需要判斷 l1 是 null let val2 = l2 ? l2.val || 0 : 0; // 需要判斷 l2 是 null let sum = val1 + val2 + tmpS; // this.val 相加並加上進位值 tmpS = sum >= 10 ? 1 : 0; // 計算本次相加是否需要進位 sum = sum % 10; // 當前位只需要個位數 if(l1) l1 = l1.next; // 遍歷鏈表 if(l2) l2 = l2.next; // 遍歷鏈表 resNode.next = new ListNode(sum); // 將當前結果掛到臨時的 node 上 resNode = resNode.next; // 如果要繼續掛載鏈表,需要將當前的指針移動到 next 上 } return result.next; // result 是 resNode, resNode.next 才是最終結果 };
需要注意的是,resNode 這個鏈表,需要每次將當前的指針移動到下一個 ListNode,可以打印 resNode 觀察過程:
// 打印位置: // resNode.next = new ListNode(sum); // 將當前結果掛到臨時的 node 上 // console.log(resNode); // resNode = resNode.next; // 如果要繼續掛載鏈表,需要將當前的指針移動到 next 上 ListNode { val: 0, next: ListNode { val: 7, next: null } } ListNode { val: 7, next: ListNode { val: 0, next: null } } ListNode { val: 0, next: ListNode { val: 8, next: null } } // 打印位置: // resNode.next = new ListNode(sum); // 將當前結果掛到臨時的 node 上 // resNode = resNode.next; // 如果要繼續掛載鏈表,需要將當前的指針移動到 next 上 // console.log(resNode); ListNode { val: 7, next: null } ListNode { val: 0, next: null } ListNode { val: 8, next: null }
雖然每次 resNode 都被重新賦值,對於 result 來說,只是指針移動而已,因此它會擁有完整的鏈表。