1. 程式人生 > 其它 >第89期-基礎演算法:遞迴 合併兩個有序連結串列

第89期-基礎演算法:遞迴 合併兩個有序連結串列

1 問題描述

將兩個升序連結串列合併為一個新的 升序 連結串列並返回。新連結串列是通過拼接給定的兩個連結串列的所有節點組成的。

示例 1:


輸入:l1 = [1,2,4], l2 = [1,3,4]
輸出:[1,1,2,3,4,4]

示例 2:

輸入:l1 = [], l2 = []
輸出:[]

示例 3:

輸入:l1 = [], l2 = [0]
輸出:[0]

初始程式碼

# 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 mergeTwoLists(self,l1: ListNode, l2: ListNode) -> ListNode:
#在此填寫程式碼 if __name__ == '__main__': print(LinkList().printlist(Solution().mergeTwoLists(LinkList().initList([1,2,4]),LinkList().initList([1,3,4])))) print(LinkList().printlist(Solution().mergeTwoLists(LinkList().initList([]),LinkList().initList([])))) print(LinkList().printlist(Solution().mergeTwoLists(LinkList().initList([]),LinkList().initList([0]))))
View Code

2 解題思路

  • 標籤:遞迴
  • 終止條件:當兩個連結串列都為空時,表示我們對連結串列已合併完成。
  • 如何遞迴:我們判斷 l1 和 l2 頭結點哪個更小,然後較小結點的 next 指標指向其餘結點的合併結果。(呼叫遞迴)
  • 則當前位的值為(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 mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        import math
        if not l1 and not l2:return 
        if (l1.val if l1 else math.inf) <(l2.val if l2 else math.inf):
            node=ListNode(l1.val)
            node.next=self.mergeTwoLists(l1.next,l2)
        else:
            node=ListNode(l2.val)
            node.next=self.mergeTwoLists(l1,l2.next)
        return node

if __name__ == '__main__':
    print(LinkList().printlist(Solution().mergeTwoLists(LinkList().initList([1,2,4]),LinkList().initList([1,3,4]))))
    print(LinkList().printlist(Solution().mergeTwoLists(LinkList().initList([]),LinkList().initList([]))))
    print(LinkList().printlist(Solution().mergeTwoLists(LinkList().initList([]),LinkList().initList([0]))))
View Code

第1-30,41-44行:題目中已經給出的資訊,執行程式碼時要根據這些程式碼進行編輯
第31行:引入math模組(後面會用到)
第32行:當兩個連結串列都遍歷完時,結束函式遞迴
第33行:判斷l1與l2當前節點值的大小(若不存在則節點值大小為無窮大(math.inf為無窮大))
第34行:若l1節點值小於l2節點值,則用l1節點值新建一個連結串列node
第35行:連結串列node的下一個元素進行遞迴操作,內部變數分別為l1連結串列的後一段連結串列以及l2連結串列
第36-38行:若l1節點值大於或等於於l2節點值,則用l2節點值新建一個連結串列node,並進行遞迴操作
第37行:返回node連結串列

程式碼執行結果為:

#演算法講解

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


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


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

#結構講解

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

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