例題:
leetcode 445. 兩數相加 II
給定兩個非空鏈表來代表兩個非負整數。數字最高位位於鏈表開始位置。它們的每個節點只存儲單個數字。將這兩數相加會返回一個新的鏈表。
你可以假設除了數字 0 之外,這兩個數字都不會以零開頭。
進階:
如果輸入鏈表不能修改該如何處理?換句話說,你不能對列表中的節點進行翻轉。
示例:
輸入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出: 7 -> 8 -> 0 -> 7
1. 使用C++引用傳遞,函數調用過程中修改的都是同一個地址空間中保存到carry值(進位值)
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int len1 = get_length(l1), len2 = get_length(l2);
int len = max(len1, len2);
if(len1 != len2){
ListNode* head = len1 < len2 ? l1 : l2;
for(int i = 0; i < len - min(len1, len2); i ++){
ListNode* node = new ListNode(0);
node->next = head;
head = node;
}
if(len1 < len2) l1 = head;
else l2 = head;
}
int carry = 0;
ListNode* res = go(l1, l2, carry);
if(carry){
ListNode* node = new ListNode(1);
node->next = res;
res = node;
}
return res;
}
private:
int get_length(ListNode* head){
if(!head) return 0;
return 1 + get_length(head->next);
}
ListNode* go(ListNode* l1, ListNode* l2, int& carry){ //使用引用傳遞
if(!l1){
assert(!l2);
carry = 0;
return NULL;
}
ListNode* next = go(l1->next, l2->next, carry); //遞歸調用,carry 使用引用傳遞
int x = l1->val + l2->val + carry; //遞歸調用過程中使用的都是同一個地方的carry值
ListNode* res = new ListNode(x % 10);
res->next = next;
carry = x / 10;//遞歸調用過程中修改的都是同一個地方的carry值
return res;
}
};
2. 在python中跟上面C++一樣的寫法就是錯的
錯誤的代碼:
def addTwoNumbers2(l1: ListNode, l2: ListNode) -> ListNode:
def get_len(head):
if not head:
return 0
return 1 + get_len(head.next)
def add(l1,l2,carry):
if not l1:
carry = 0
return None
next = add(l1.next, l2.next,carry) ## !!!!
sum = l1.val + l2.val + carry ## !!!! 無法獲取在下一層調用中更新的carry值,這裏的這一層函數中的carry值仍然是0
node = ListNode(sum%10)
node.next = next
carry = sum // 10 ## !!!!
return node
len1, len2 = get_len(l1), get_len(l2)
len = max(len1,len2)
head = l1 if len1 < len2 else l2
for i in range(len - min(len1,len2)):
node = ListNode(0)
node.next = head
head = node
if len1 < len2:
l1 = head
else:
l2 = head
carry = 0
res = add(l1,l2,carry)
if carry:
node = ListNode(carry)
node.next = res
res = node
return res
錯誤的原因:因爲python中每次遞歸函數調用傳遞的都是不可變對象(進位值,是一個數值常量),當在函數中 更新carry = x // 10 時,只是該函數內部空間的局部變量(標籤)carry又綁定到了另一個不可變對象 x // 10上了,該函數返回到上一級函數中,上一級函數內部空間的局部變量(標籤)carry仍然綁定在原來綁定的不可變對象0上,也就是說在python中,這種函數參數傳遞方式在遞歸調用中無法獲取下一層中的carry更新值
正確的代碼:
遞歸函數返回本層函數調用更新後的carry值
class Solution:
def addTwoNumbers(self, l1, l2):
def add(num1, num2, i, j):
if not i or not j:
return 0
if num1 > num2:
temp = i.val + add(num1 - 1, num2, i.next, j)
else:
temp = i.val + j.val + add(num1, num2, i.next, j.next)
i.val = temp % 10
return temp // 10 # 遞歸函數返回本層函數調用更新後的carry值
num1 = num2 = 0
cur = l2
while cur:
num2 += 1
cur = cur.next
cur = l1
while cur:
num1 += 1
cur = cur.next
if num2 > num1:
l1, l2 = l2, l1
num2, num1 = num1, num2
if add(num1,num2,l1, l2):
l2 = ListNode(1)
l2.next = l1
l1 = l2
return l1