1. 程式人生 > 其它 >第88期-基礎演算法:遞迴 兩數相加

第88期-基礎演算法:遞迴 兩數相加

1 問題描述

給你兩個非空 的連結串列,表示兩個非負的整數。它們每位數字都是按照逆序的方式儲存的,並且每個節點只能儲存一位數字。
請你將兩個數相加,並以相同形式返回一個表示和的連結串列。
你可以假設除了數字 0 之外,這兩個數都不會以 0開頭。

示例 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]

初始程式碼

# Definition for singly-linked list.
class ListNode: def __init__(self, x): self.val = x self.next = None class LinkList: def __init__(self): self.head=None def initList(self, data): while len(data)==0:return None self.head = ListNode(data[0]) r=self.head p = self.head
for i in data[1:]: node = ListNode(i) p.next = node p = p.next return r def printlist(self,head): a=[] if head == None: return [] node = head while node != None: a.append(node.val) node = node.next
return a class Solution: def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: #在此之間填寫程式碼 if __name__ == '__main__': print(LinkList().printlist(Solution().addTwoNumbers(LinkList().initList([2,4,3]),LinkList().initList([5,6,4])))) print(LinkList().printlist(Solution().addTwoNumbers(LinkList().initList([0]),LinkList().initList([0])))) print(LinkList().printlist(Solution().addTwoNumbers(LinkList().initList([9,9,9,9,9,9,9]),LinkList().initList([9,9,9,9]))))
View Code

2 解題思路

  • 標籤:遞迴
  • 根據題意可知連結串列數字位數是從小到大的
  • 因為兩個數字相加會產生進位,所以使用i來儲存進位。
  • 則當前位的值為(l1.val + l2.val + i) % 10
  • 則進位值為(l1.val + l2.val + i) / 10
  • 建立新node,然後將進位傳入下一層。

#3 解題方法

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
 
class LinkList:
    def __init__(self):
        self.head=None
 
    def initList(self, data):
        while len(data)==0:return None
        self.head = ListNode(data[0])
        r=self.head
        p = self.head
        for i in data[1:]:
            node = ListNode(i)
            p.next = node
            p = p.next
        return r
    def printlist(self,head):
        a=[]
        if head == None: return []
        node = head
        while node != None:
            a.append(node.val)
            node = node.next
        return a
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        def dfs(l, r, i):
            if not l and not r and not i: return None
            s = (l.val if l else 0) + (r.val if r else 0) + i
            node = ListNode(s % 10)
            node.next = dfs(l.next if l else None, r.next if r else None, s // 10)
            return node
        return dfs(l1, l2, 0)

if __name__ == '__main__':
    print(LinkList().printlist(Solution().addTwoNumbers(LinkList().initList([2,4,3]),LinkList().initList([5,6,4]))))
    print(LinkList().printlist(Solution().addTwoNumbers(LinkList().initList([0]),LinkList().initList([0]))))
    print(LinkList().printlist(Solution().addTwoNumbers(LinkList().initList([9,9,9,9,9,9,9]),LinkList().initList([9,9,9,9]))))
View Code

第1-30,39-42行:題目中已經給出的資訊,執行程式碼時要根據這些程式碼進行編輯
第31行:定義函式dfs,其內部變數l,r,i分別代表第一個連結串列,第二個連結串列已經他們和的十位數
第32行:當兩個連結串列都遍歷完且十位數也為0時,結束函式遞迴
第33行:定義變數s,若連結串列存在,則加上鍊表該位置的值,不存在則加0,再加上i的值(即兩個數想加大於十時向前進一)
第34行:定義連結串列node,為剛才和的個位數
第35行:連結串列node的下一個元素進行遞迴操作,內部變數分別為之前兩個連結串列的後一個元素以及剛剛和的十位數
第36行:返回連結串列
第37行:使用dfs函式對題目中的連結串列進行操作

程式碼執行結果為:

#演算法講解

這裡用到了基礎演算法:遞迴,簡單講解下這個演算法:
什麼是遞迴
程式呼叫自身的程式設計技巧稱為遞迴
遞迴做為一種演算法在程式設計語言中廣泛應用。


遞迴演算法一般用於解決三類問題:
(1)資料的定義是按遞迴定義的。(Fibonacci函式)
(2)問題解法按遞迴演算法實現。
(3)資料的結構形式是按遞迴定義的。


遞迴函式特徵
必須有一個明確的結束條件;
每次進入更深一層遞迴時,問題規模相比上次遞迴都應有所減少
相鄰兩次重複之間有緊密的聯絡,前一次要為後一次做準備(通常前一次的輸出就作為後一次的輸入)。
遞迴效率不高,遞迴層次過多會導致棧溢位(在計算機中,函式呼叫是通過棧(stack)這種資料結構實現的,每當進入一個函式呼叫,棧就會加一層棧幀,每當函式返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞迴呼叫的次數過多,會導致棧溢位)

#結構講解

這裡用到了基礎結構:連結串列,簡單講解下這個連結串列:
連結串列
連結串列是一組資料項的集合,其中每個資料項都是一個節點的一部分,每個節點還包含指向下一個節點的連結
連結串列的結構:data為自定義的資料,next為下一個節點的地址。

基本元素
節點:每個節點有兩個部分,左邊稱為值域,存放使用者資料;右邊部分稱為指標域,用來存放指向下一個元素的指標。
head:head節點永遠指向第一個節點
tail: tail永遠指向最後一個節點
None:連結串列中最後一個節點的指標域為None值