「@Author:Runsen」node
❝編程的本質來源於算法,而算法的本質來源於數學,編程只不過將數學題進行代碼化。「---- Runsen」git
❞
最近在從新梳理學算法的知識,本文爲鏈表常見操做複習的總結文章,會講解常見的鏈表題目實現思路及附上答案,這些題目在leetcode上對應的題號也有給出,好好學習算法吧~github
-
單鏈表反轉 -
鏈表中環的檢測 -
兩個有序的鏈表合併 -
K個有序的鏈表合併
leetcode 對應題號:206,141,21,23web
LeetCode 第 206 題:反轉鏈表
反轉一個單鏈表。面試
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
題目不難,定義三個變量pre、cur、cur.next,分別記錄上一個結點,當前結點、下一個結點。算法
反轉一個單鏈表須要當前節點的next指針指向上一個結點pre,當前節點的指針指向下一個結點,上一個結點的指針指向當前節點。編程
經過迭代,依次反轉結點指向。具體代碼以下小程序
class Solution:
def reverseList(self, head):
cur, prev = head, None
while cur:
cur.next, prev, cur = prev, cur, cur.next
return prev
LeetCode 第 141 題:判斷鏈表中是否有環
遍歷整個數組, 給出的數據包含在集合中則說明有環, 返回 True; 若遍歷完畢, 則說明無環, 返回 False,若是用列表也是同樣。數組
「暴力解法」微信
class Solution:
def hasCycle(self, head: ListNode) -> bool:
"""
暴力法:經過遍歷鏈表,用set來存儲訪問的節點,若是在set出現同樣的節點,說明有壞,時間複雜度O(n)
:type head: ListNode
:rtype: bool
"""
st = set()
while head:
if head in st:
return True
st.add(head)
head = head.next
return False
# 下面是列表
l = []
while head:
if head in l:
return True
else:
l.append(head)
head = head.next
return False
從頭遍歷到尾,發現指向null,說明沒環。這明顯不靠譜。暴力的時間空間複雜度都是O(n)
題目要求用 空間複雜度。其實,這道題考的是「快慢指針」 空間複雜度
經過使用具備 不一樣速度 的快、慢兩個指針遍歷鏈表,空間複雜度能夠被下降至 。慢指針每次移動一步,而快指針每次移動兩步。
若是列表中不存在環,最終快指針將會最早到達尾部,此時咱們能夠返回 false。
能夠想象這樣一個場景, 你和一個朋友一塊兒散步, 你每次移動兩步, 朋友每次一步, 如爲單向定長道路, 你必然先到達重點. 如果環繞操場,則大家終將相遇.
class Solution(object):
def hasCycle(self, head):
slow = fast = head
while slow and fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
LeetCode 第21題:合併兩個有序鏈表
將兩個升序鏈表合併爲一個新的 升序 鏈表並返回。新鏈表是經過拼接給定的兩個鏈表的全部節點組成的。
示例:
輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4
從兩鏈表第一個結點開始比較結點的值,取較小者做爲合併鏈表的元素,依次進行;後面若是有一個鏈表爲空,則直接把不爲空的鏈表接到合併鏈表的後面。
這個解決的方法使用遞歸,若是L1爲空就返回L2,L2爲空返回L1,L1的val<=L2的val,那麼繼續遞歸。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
#遞歸的結束點就是L1或者L2爲空就返回
#若是L1爲空就返回L2,L2爲空返回L1
# if not (l1 and l2):
# return l1 if l1 else l2
if not l1:
return l2
elif not l2:
return l1
#L1的val<=L2的val,那麼繼續遞歸
#當前L1的next指向一個遞歸函數
#意思是L1的下一個和L2哪一個大,就做爲當前L1的next
elif l1.val<=l2.val:
l1.next = self.mergeTwoLists(l1.next,l2)
return l1
else:
l2.next = self.mergeTwoLists(l1,l2.next)
return l2
遞歸的代碼看起來是十分簡潔的
LeetCode 第 23 題:合併 k 個排序鏈表
合併 k 個排序鏈表,返回合併後的排序鏈表。請分析和描述算法的複雜度。
示例:
輸入:
[
1->4->5,
1->3->4,
2->6
]
輸出: 1->1->2->3->4->4->5->6
第一種法就是常規暴力思路,直接將全部的元素取出,而後排個序,再重組就達到了目的。
遍歷全部鏈表,將全部節點的值放到一個數組中。將這個數組排序,而後遍歷全部元素獲得正確順序的值。用遍歷獲得的值,建立一個新的有序鏈表。
時間複雜度: ,其中 N 是節點的總數目
空間複雜度: 。
排序花費 空間(這取決於你選擇的算法)。建立一個新的鏈表花費 的空間。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode :
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
self.nodes = []
head = point = ListNode(0)
for l in lists:
while l:
self.nodes.append(l.val)
l = l.next
for x in sorted(self.nodes):
point.next = ListNode(x)
point = point.next
return head.next
「人生最重要的不是所站的位置,而是心裏所朝的方向。只要我在每篇博文中寫得本身體會,修煉身心;在天天的不斷重複學習中,耐住寂寞,練就真功,不畏艱難,奮勇前行,不忘初心,砥礪前行,人生定會有所收穫,不留遺憾 (做者:Runsen )」
❝本文已收錄 GitHub,傳送門~[1] ,裏面更有大廠面試完整考點,歡迎 Star。
❞
Reference
傳送門~: https://github.com/MaoliRUNsen/runsenlearnpy100
更多的文章
點擊下面小程序
- END -
本文分享自微信公衆號 - Python之王(sen13717378202)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。