前言
這道題將整數加法轉換為在單連結串列上做加法運算,涉及到知識點:
- 單連結串列的遍歷
- 單連結串列插入新節點
題目描述
給你兩個 非空 的連結串列,表示兩個非負的整數。它們每位數字都是按照 逆序 的方式儲存的,並且每個節點只能儲存 一位 數字。
示例1:
輸入:l1 = [2,4,3], l2 = [5,6,4]
輸出:[7,0,8]
解釋:342 + 465 = 807.
示例2:
輸入:l1 = [0], l2 = [0]
輸出:[0]
示例3:
輸入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
輸出:[8,9,9,9,0,0,0,1]
提示
-
每個連結串列中的節點數在範圍
[1, 100]
內 -
0 <= Node.val <= 9
-
題目資料保證列表表示的數字不含前導零
題目分析
單連結串列遍歷只能 單向單步:給定一個節點的指標,那麼它只能訪問下一個節點的內容。單連結串列的遍歷時間複雜度唯一: \(\mathcal{O}(n)\) 。
注意到:由於每個節點只能儲存一位數字,那麼兩個對應位相加的最大值為 \(9 + 9 = 18\) ,因此我們的十進位制 進位
最大隻會為 1 。
暴力演算法
就像普通的十進位制數加法一樣,每一位相加後對 \(10\) 取餘作為當前位的答案,而對 \(10\) 取商作為進位。遍歷完後還需要判斷是否進位不為 \(0\) ,如果不為 \(0\) ,就還需要增加數字為 \(1\) 的節點。
假設 \(A\) 代表 \(L_1\) 連結串列, \(B\) 代表 \(L_2\) 連結串列, \(C\) 代表 \(L_1\) 與 \(L_2\) 的和 :
\[C = A + B \\
\]
因此給出數學公式:
\[\begin{equation}
\begin{aligned}
\begin{cases}
C_i &= A_i + B_i + t(\text{進位}),\qquad &0\leq i\leq max(A.length , B.length)\\
\\
\\
C_i &= 1, & t = 1 ,\quad i = max(A.length , B.length) + 1
\end{cases}
\end{aligned}
\end{equation}
\]
解題程式碼
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* head = new ListNode();
ListNode* cur = head;
int t = 0;
while ( l1 || l2) {
if ( l1) {
t += l1->val;
l1 = l1->next;
}
if ( l2) {
t += l2->val;
l2 = l2->next;
}
ListNode* nnew = new ListNode(t % 10);
cur->next = nnew;
t /= 10;
cur = cur->next; // 準備下一次的增加新節點
}
if ( t ) {
ListNode* nnew = new ListNode(1);
cur->next = nnew;
}
return head->next;
}
};
複雜度分析
\[\begin{equation}\begin{aligned}
\mathcal{O}(Complex) &= \mathcal{O}(\text{單個節點處理:申請節點,插入節點})\\
&+\mathcal{O}(遍歷) \\
&= \mathcal{O}(k\times n) + \mathcal{O}(n )\\
\end{aligned}\end{equation}
\]
最終我們的時間複雜度為 \(\mathcal{O}(n)\) 。
我們在剛開始刷題的時候,可以先試著自己寫出暴力演算法,然後分析一下時間複雜度,再嘗試其他解題方法。