python 關於變量賦值 與 函數參數傳遞(三) ——VS C++

例題:

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章