一、思路
給定兩個非空鏈表來代表兩個非負整數。數字最高位位於鏈表開始位置。它們的每個節點只存儲單個數字。將這兩數相加會返回一個新的鏈表。舉例:
輸入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出: 7 -> 8 -> 0 -> 7
抽象至邏輯結構的層面,實際上就是豎式加法。從低位向高位進行計算,額外的進位也需要加上。麻煩就麻煩在,存儲結構是鏈表,只進行順序存取(無法倒退),也即不能直接使用兩根指針分別遍歷到最低位然後倒退着相加了。可以用棧幫助我們完成倒退,也可以使用連續的數據結構例如字符串(性質是隨機存取,靈活性高於順序存取)完成倒退的動作。
1.1 知識點
棧的性質,後進先出。本條性質本身就有逆序(反轉、倒退,表述是同一個意思)的效果。
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
if (!l1 || !l2) return !l1 ? l2 : l1; //處理兩鏈表存在空表的情況
stack<int> stk1, stk2;
while (l1) {
stk1.push(l1->val);
l1 = l1->next;
}//表1入棧
while (l2) {
stk2.push(l2->val);
l2 = l2->next;
}//表2入棧
ListNode *dummy = new ListNode(0); //創建啞結點,統一新表的結點插入
ListNode *current = NULL; //指向新創建的結點
int carry = 0, n1, n2, sum; //標記進位、鏈表1和2的1位數字、1位數之和
while (!stk1.empty() || !stk2.empty() || carry) {
if (stk1.empty()) n1 = 0;
else { n1 = stk1.top(); stk1.pop(); } //從表1取出1位
if (stk2.empty()) n2 = 0;
else { n2 = stk2.top(); stk2.pop(); } //從表2取出1位
sum = n1 + n2 + carry; //記錄本輪1位數之和
carry = sum / 10; //記錄本輪進位
//尾插法建立新的鏈表(逆序)
current = new ListNode(sum % 10);
current->next = dummy->next;
dummy->next = current;
} //存在非空的棧,或者存在進位循環繼續進行
ListNode *retNode = dummy->next;
delete dummy;
return retNode;
}
1.2 知識點
字符串具有極好的性質——隨機存取。也即我們可以在字符串中進行相關計算,最後在創建新表的時候,寫入數據。
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
string str1, str2; //依次寫入字符串中
while (l1) { str1 += to_string(l1->val); l1 = l1->next; }
while (l2) { str2 += to_string(l2->val); l2 = l2->next; }
//加法
string ans;
int carry = 0, i = str1.size() - 1, j = str2.size() - 1;
while (i >= 0 || j >= 0 || carry) {
if (i >= 0) carry += str1[i--] - '0';
if (j >= 0) carry += str2[j--] - '0';
ans = to_string(carry % 10) + ans;
carry /= 10;
}
//頭插法建立新鏈表
ListNode *dummy = new ListNode(0);
ListNode *prev = dummy;
for (auto i : ans) {
ListNode *current = new ListNode(i - '0');
prev->next = current;
prev = current;
}
ListNode *retNode = dummy->next;
delete dummy; //釋放啞結點
return retNode;
}