當前Leetcode的鏈表標簽題目一共53道題,除了會員題目,題解基本都在這了,還可能陸續更新一題多解~
簡單
(1)刪除節點
面試題 02.03. 刪除中間節點
同
237. 刪除鏈表中的節點
- 如果當前節點有下一個節點,下一個節點也有下一個節點,那么把當前這個節點的值變為下一個節點的值,當前節點直接指向下一個節點的下一個節點(相當于刪除的不是當前節點,而是把當前節點變成它下一個節點,把它下一個節點刪除)
- 如果當前節點有下一個節點,但是下一個節點沒有下一個節點了(當前節點是鏈表的倒數第二個節點),那么把當前節點的值變成下一個節點的值,當前節點指向None(還是相當于刪除了下一個節點)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
if node.next:
if node.next.next:
node.val = node.next.val
node.next = node.next.next
else:
node.val = node.next.val
node.next = None
# 這一行有沒有都可以通過,因為當前節點不為最后一個節點,而且不要求返回
return None
-------------------------------------------------------------------------------------------------
# 也可以:
if node.next:
node.val = node.next.val
if node.next.next:
node.next = node.next.next
else:
node.next = None
面試題 02.01. 移除重復節點
同
83. 刪除排序鏈表中的重復元素
- 用字典保存節點的值,新建一個鏈表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeDuplicateNodes(self, head: ListNode) -> ListNode:
mydict = {}
newhead = ListNode(0)
n = newhead
h = head
while h:
if h.val not in mydict:
mydict[h.val] = True
n.next = ListNode(h.val)
n = n.next
h = h.next
return newhead.next
原地:
- 新建節點作為新的頭節點,它的next為head
- 使用兩個指針一個字典
- 第一個指針指向新的頭節點,第二個節點往下遍歷,當遇到有新的值的節點,把第一個節點的next指向這個節點,把第一個節點指向這個節點,把這個節點的值加到字典中,第二個節點繼續往下遍歷
- 如果第二個指針遇到當前節點的值已經在字典中了,繼續往下遍歷
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeDuplicateNodes(self, head: ListNode) -> ListNode:
mydict = {}
newhead = ListNode(0)
newhead.next = head
cur = newhead
nex = cur.next
while nex:
if nex.val not in mydict:
cur.next = nex
mydict[nex.val] = True
cur = cur.next
nex = nex.next
cur.next = None
return newhead.next
203. 移除鏈表元素
- 同樣的方法,題目稍有不同:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
newhead = ListNode(0)
newhead.next = head
cur = newhead
nex = cur.next
while nex:
if nex.val != val:
cur.next = nex
cur = cur.next
nex = nex.next
cur.next = None
return newhead.next
劍指 Offer 18. 刪除鏈表的節點
- 和上面一樣。。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, head: ListNode, val: int) -> ListNode:
newhead = ListNode(0)
newhead.next = head
cur, nex = newhead, newhead.next
while nex:
if nex.val != val:
cur.next = nex
cur = cur.next
nex = nex.next
cur.next = None
return newhead.next
(2)反轉鏈表
206. 反轉鏈表
同
劍指 Offer 24. 反轉鏈表
把第一個節點指向newhead
newhead指向cur
cur指向nex
nex指向它的下一個
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head:
return None
newhead = None
cur = head
nex = cur.next
while cur:
cur.next = newhead
newhead = cur
cur = nex
if nex:
nex = nex.next
return newhead
(3)雙指針:中間節點、環形鏈表
876. 鏈表的中間結點
- 定義一個快指針一個慢指針,快指針每次走兩步,慢指針每次走一步,當快指針到鏈表的尾時,慢指針所在的位置就是鏈表的中間節點
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def middleNode(self, head: ListNode) -> ListNode:
fast = head
slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
return slow
劍指 Offer 22. 鏈表中倒數第k個節點
- 雙指針,一個快指針,一個慢指針
- 快指針先走k步,走完k步之后,再和慢指針一起,每次走一步,當快指針到達鏈表的尾時,慢指針所在的位置就是要返回的倒數第k個節點
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
if not head:
return None
fast = head
slow = head
while k > 0:
fast = fast.next
k -= 1
while fast:
fast = fast.next
slow = slow.next
return slow
面試題 02.02. 返回倒數第 k 個節點
- 與上一題稍有不同,返回的是節點的值
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def kthToLast(self, head: ListNode, k: int) -> int:
if not head:
return None
fast, slow = head, head
while k > 0:
fast = fast.next
k -= 1
while fast:
fast = fast.next
slow = slow.next
return slow.val
環形鏈表:
141. 環形鏈表
- 一個快指針一個慢指針,快指針每次走兩步,慢指針每次走一步,如果快指針和慢指針走著走著相遇了,說明有環,返回True,否則返回False
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
兩個鏈表
21. 合并兩個有序鏈表
- 如果兩個鏈表中有一個為空,直接返回另一個鏈表即可(如果兩個都為空,那么返回其中哪一個都是返回一個空鏈表)
- 定義一個newhead,定義一個指針cur指向newhead
- 兩個指針,一個指向l1的頭,一個指向l2的頭,比較當這兩個指針都不為空時,比較這兩個指針指向的節點的值,把較小的賦給cur,然后繼續遍歷
- 當這兩個指針中有一個為空了,把不為空的那個指針指向的節點以及它以后的節點賦給cur
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not l1 or not l2:
return l2 or l1
tmp1, tmp2 = l1, l2
newhead = ListNode(0)
cur = newhead
while tmp1 and tmp2:
if tmp1.val > tmp2.val:
cur.next = tmp2
tmp2 = tmp2.next
else:
cur.next = tmp1
tmp1 = tmp1.next
cur = cur.next
if tmp1:
cur.next = tmp1
else:
cur.next = tmp2
return newhead.next
(4)反轉鏈表和雙指針
234. 回文鏈表
同
面試題 02.06. 回文鏈表
- 先用雙指針找到鏈表的中間節點,把從它的這個節點開始以后的節點組成的鏈表(也就是整個鏈表的后半部分)反轉
- 雙指針:一個快指針一個慢指針,慢指針每次走一步,快指針每次走兩步,當快指針到達結尾的時候,慢指針所在的位置就是中間節點。要注意快指針的邊界,當快指針的不是None,而且快指針的下一個也不是None才可以繼續往下走。
- 比較前半部分和反轉后的后半部分,這兩個鏈表中只要有一個鏈表遍歷到結尾就可以結束遍歷,因為不管這個鏈表的節點是奇數個還是偶數個,都可以是一個回文鏈表
也就是例如 1——>2——>3——>2——>1,分成兩個鏈表分別是1——>2和1——>2——>3比較,只要1,2相同即可。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if not head:
return True
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
newhead = None
cur = slow
nex = cur.next
while cur:
cur.next = newhead
newhead = cur
cur = nex
if nex:
nex = nex.next
h = head
while h and newhead:
if h.val == newhead.val:
h = h.next
newhead = newhead.next
else:
return False
return True
(5)雙指針解決兩個鏈表相交問題
160. 相交鏈表
同
劍指 Offer 52. 兩個鏈表的第一個公共節點
同
面試題 02.07. 鏈表相交
- 兩個指針,一個指針A從鏈表A的頭開始走,另外一個指針B,從鏈表B的頭開始走,當A或B走完自己的鏈表時,繼續走對方的鏈表,如果指針A和指針B相遇了,返回指針A(這時候的返回有兩種情況,一是有環的情況,AB相遇的位置是兩個鏈表的第一個公共節點,二是沒有環的情況,這時候返回的是None,因為AB都同時走了一樣的路程:鏈表A和B,到達了終點相遇)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if not headA or not headB:
return None
tmpA, tmpB = headA, headB
while tmpA != tmpB:
if tmpA:
tmpA = tmpA.next
else:
tmpA = headB
if tmpB:
tmpB = tmpB.next
else:
tmpB = headA
return tmpA
(6)其他
劍指 Offer 06. 從尾到頭打印鏈表
- 遍歷,把節點的值存在列表中,返回列表的逆序即可
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
res = []
h = head
while h:
res.append(h.val)
h = h.next
return res[::-1]
1290. 二進制鏈表轉整數
舉例:
如果輸入是[1,0,0,1,0],它的十進制樹應該是18.
那么二進制轉成十進制是這么算的:
定義一個res用來返回結果,每當遍歷到一個新的節點,就把前面res的值*2再加上當前節點的值:
這樣第一個1一共乘了四個2,第二個1一共乘了一個2,加在一起正好是返回的結果。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getDecimalValue(self, head: ListNode) -> int:
res = 0
cur = head
while cur:
res = res * 2 + cur.val
cur = cur.next
return res
中等
(1)刪除節點
82. 刪除排序鏈表中的重復元素 II
- 時間復雜度是O(n),空間復雜度小于O(n)
- 用一個字典來保存每一個節點的值出現了多少次
- 利用雙指針刪除節點
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
mydict = {}
cur = head
newhead = ListNode(0)
newhead.next = head
while cur:
if cur.val in mydict:
mydict[cur.val] += 1
else:
mydict[cur.val] = 1
cur = cur.next
cur = newhead
nex = cur.next
while nex:
if mydict[nex.val] == 1:
cur.next = nex
cur = cur.next
nex = nex.next
cur.next = None
return newhead.next
因為是排序鏈表,還可以使用三指針:
參考:
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/solution/chao-qing-xi-tu-jie-san-zhi-zhen-fa-by-justdo1t/
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
newhead = ListNode(0)
newhead.next = head
cur, left, right = newhead, newhead.next, newhead.next
while right:
while right.next and right.next.val == right.val:
right = right.next
if right == left:
cur.next = left
cur = cur.next
left = right.next
right = left
cur.next = None
return newhead.next
19. 刪除鏈表的倒數第N個節點
- 雙指針
- 因為被刪除的節點至少是“倒數第一個”節點,所以如果鏈表本身就為空,那就直接返回空,鏈表本身只有一個節點,一定會刪除倒數第一個節點,所以也返回空
- 快指針先走n個節點,如果這時fast為空,說明fast正好走完了鏈表,那么n既鏈表節點數,也就是長度為n的鏈表,刪除倒數第n個節點,也就是刪除第一個節點,這時直接返回head.next
- 如果fast先走n步,走完fast不為空,那么fast和slow一起繼續走,并且循環while的條件是fast與fast.next都不為空,也就是fast最遠走到最后一個節點
- 因為fast比slow走得快,所以可以保證slow.next一定存在,當fast走到最后一個節點,此時slow所在的位置就是被刪除節點的前一個節點,此時只要將slow.next指向slow.next.next,因為slow.next一定存在(如上述),所以slow.next指向slow.next.next不會報錯
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
if not head or not head.next:
return None
slow, fast = head, head
while n > 0:
fast = fast.next
n -= 1
if not fast:
return head.next
while fast and fast.next:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return head
(2)變換鏈表
24. 兩兩交換鏈表中的節點
- 三個指針
- 新建個頭節點newhead,newhead的next指向head
- 用四個指針,cur,cur1,cur2,nex
- cur初始指向newhead,cur1指向head的第一個節點,cur2指向head的第二個節點,nex指向第三個
- 把cur的next指向cur2,cur2的next指向cur1,cur1的next指向None,就完成了兩個節點的翻轉
- 然后把cur1指向nex,cur2指向cur1的next,nex指向cur2的next
- 注意退出循環的條件
- 退出循環后,如果cur1還指向某個節點,要把這個節點加到鏈表的尾部
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
cur1, cur2 = head, head.next
nex = cur2.next
newhead = ListNode(0)
newhead.next = head
cur = newhead
while cur1 and cur2:
cur.next = cur2
cur2.next = cur1
cur = cur1
cur.next = None
cur1 = nex
if cur1 and cur1.next:
cur2 = cur1.next
else:
break
nex = cur2.next
if cur1:
cur.next = cur1
return newhead.next
61. 旋轉鏈表
- 先遍歷一遍鏈表計算鏈表的長度
- 把k和長度取余,然后使用快慢指針找到要旋轉的節點,拼接一下即可
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def rotateRight(self, head: ListNode, k: int) -> ListNode:
if k == 0 or not head:
return head
lenth = 0
h = head
while h:
lenth += 1
h = h.next
lenth = k % lenth
if lenth == 0:
return head
fast = head
slow = head
while lenth > 0:
fast = fast.next
lenth -= 1
pivot = fast
while fast and fast.next:
fast = fast.next
slow = slow.next
pivot = pivot.next
newhead = slow.next
slow.next = None
pivot.next = head
return newhead
148. 排序鏈表
- 歸并,把每個節點都分成一個一個節點
- 再把兩個兩個排好序拼在一起
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def sortList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
fast, slow = head.next, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
right_head = slow.next
slow.next = None
left, right = self.sortList(head), self.sortList(right_head)
return self.merge(left, right)
# 合并兩個鏈表
def merge(self, head1, head2):
h1, h2 = head1, head2
newhead = ListNode(0)
cur = newhead
while h1 and h2:
if h1.val > h2.val:
cur.next = h2
h2 = h2.next
else:
cur.next = h1
h1 = h1.next
cur = cur.next
cur.next = h1 or h2
return newhead.next
86. 分隔鏈表
同
面試題 02.04. 分割鏈表
- 新建兩個頭節點,一個用來保存比x小的節點,另一個用來保存其他的節點
- 最后把這兩個鏈表合并即可
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def partition(self, head: ListNode, x: int) -> ListNode:
before, after = ListNode(0), ListNode(0)
cur1, cur2 = before, after
h = head
while h:
if h.val < x:
cur1.next = h
cur1 = cur1.next
else:
cur2.next = h
cur2 = cur2.next
h = h.next
cur2.next = None
cur1.next = after.next
return before.next
92. 反轉鏈表 II
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
newhead = ListNode(0)
newhead.next = head
pre = newhead
for _ in range(m - 1):
pre = pre.next
tmp_head = None
cur = pre.next
for _ in range(n - m + 1):
nex = cur.next
cur.next = tmp_head
tmp_head = cur
cur = nex
pre.next.next = cur
pre.next = tmp_head
return newhead.next
109. 有序鏈表轉換二叉搜索樹
- 遍歷鏈表找到中點,中點的值作為一個根,這個節點的左節點是左半邊鏈表的中點,右節點是這個點右半邊鏈表的中點
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def sortedListToBST(self, head: ListNode) -> TreeNode:
if not head:
return None
if not head.next:
return TreeNode(head.val)
fast, slow = head.next.next, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
root = TreeNode(slow.next.val)
root.right = self.sortedListToBST(slow.next.next)
slow.next = None
root.left = self.sortedListToBST(head)
return root
328. 奇偶鏈表
- 把head作為奇鏈表的頭和尾
- 把head.next作為偶鏈表的頭和尾
- 遍歷鏈表,當奇偶鏈表的尾還有下一個元素,就繼續遍歷
-
初始情況如下
image.png -
奇鏈表的尾的下一個節點總是偶節點,偶鏈表的尾的下一個節點總是奇節點,所以把奇鏈表的尾指向偶鏈表的尾的下一個節點,把奇鏈表的尾移到這個節點,再把偶鏈表的尾指向奇鏈表的尾的下一個節點,把偶鏈表的尾移到這個節點
image.png
image.png
image.png
image.png -
當奇鏈表的尾的下一個和偶鏈表的尾的下一個都為空時,把奇鏈表的尾的下一個指向偶鏈表的頭即可
image.png
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
odd_head = head
odd_tail = head
even_head = head.next
even_tail = head.next
while odd_tail.next and even_tail.next:
odd_tail.next = even_tail.next
odd_tail = odd_tail.next
even_tail.next = odd_tail.next
even_tail = even_tail.next
odd_tail.next = even_head
return odd_head
143. 重排鏈表
- 找到鏈表的中間節點,把后半部分反轉
- 穿插合并前半條鏈表和后半條鏈表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: ListNode) -> None:
"""
Do not return anything, modify head in-place instead.
"""
if not head:
return head
# 找到鏈表的中間節點
fast, slow = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
# 反轉后半部分鏈表
cur = slow.next
slow.next = None
newhead = None
while cur:
nex = cur.next
cur.next = newhead
newhead = cur
cur = nex
cur1 = head
cur2 = newhead
while cur1 and cur2:
nex1 = cur1.next
nex2 = cur2.next
cur1.next = cur2
cur1 = nex1
cur2.next = cur1
cur2 = nex2
return head
725. 分隔鏈表
- 先計算一下鏈表長度,如果鏈表長度大于等于要分割的塊數,如用鏈表長度除以要分割多少塊,求得每個子鏈表都需要有多少個節點partlen。再計算如果每塊都有partlen個節點,最后還剩多少節點extra,多出來的這些節點要加到每個子鏈表上,每個子鏈表加一個節點,加到extra剩余為0為止。
- 然后開始遍歷分割鏈表,把每個子鏈表的頭存到res結果集中,要把每個子鏈表的尾切割開
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
res = []
lenth, extra, part_len = 0, 0, 0
h = root
while h:
lenth += 1
h = h.next
if lenth >= k:
extra = lenth % k
part_len = lenth // k
else:
part_len = 1
cur, nex = root, root
while k > 0:
tmp_lenth = 0
k -= 1
tmp_lenth = part_len + (extra > 0)
extra = max(0, extra - 1)
res.append(nex)
while cur and tmp_lenth > 1:
tmp_lenth -= 1
cur = cur.next
if cur:
nex = cur.next
cur.next = None
cur = nex
return res
(3)環路檢測
面試題 02.08. 環路檢測
同
142. 環形鏈表 II
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
fast, slow = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
fast = head
while slow != fast:
fast = fast.next
slow = slow.next
return slow
return None
(4)求值
2. 兩數相加
同
面試題 02.05. 鏈表求和
- 核心代碼只有 while tmp1 and tmp2這一塊,就是不斷求和,注意進位
- 如果兩個鏈表中有一個遍歷完了,注意要把剩的那個列表繼續遍歷完
- 如果兩個鏈表都遍歷完了,還要注意最后是否還有進位
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
res, flag = 0, 0
tmp1, tmp2 = l1, l2
newhead = ListNode(0)
cur = newhead
while tmp1 and tmp2:
cur.next = ListNode((tmp1.val + tmp2.val + flag) % 10)
flag = (tmp1.val + tmp2.val + flag) // 10
cur = cur.next
tmp1, tmp2 = tmp1.next, tmp2.next
while tmp1:
cur.next = ListNode((tmp1.val + flag) % 10)
flag = (tmp1.val + flag) // 10
cur = cur.next
tmp1 = tmp1.next
while tmp2:
cur.next = ListNode((tmp2.val + flag) % 10)
flag = (tmp2.val + flag) // 10
cur = cur.next
tmp2 = tmp2.next
if flag > 0:
cur.next = ListNode(flag)
return newhead.next
445. 兩數相加 II
- 可以把兩個鏈表翻轉,然后按照兩數相加一的算法來做這道題目
- 使用棧(官方題解):
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
stack1, stack2 = [], []
cur = l1
while cur:
stack1.append(cur.val)
cur = cur.next
cur = l2
while cur:
stack2.append(cur.val)
cur = cur.next
flag = 0
newhead = None
while stack1 or stack2 or flag != 0 :
cur1, cur2 = 0, 0
if stack1:
cur1 = stack1.pop()
if stack2:
cur2 = stack2.pop()
tmp = cur1 + cur2 + flag
flag = tmp // 10
tmp %= 10
cur = ListNode(tmp)
cur.next = newhead
newhead = cur
return newhead
817. 鏈表組件
- 遍歷列表把每個值放在字典中
- 遍歷鏈表,如果當前的值存在在字典中,flag為0,說明當前節點是組件的第一個節點,res+1,如果當前值存在在字典中,flag為1,繼續遍歷,如果當前值不在字典中,繼續遍歷,把flag置為0
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def numComponents(self, head: ListNode, G: List[int]) -> int:
mydict = {}
for i in G:
if i not in mydict:
mydict[i] = True
cur = head
res = 0
flag = 0
while cur:
if cur.val in mydict and flag == 0:
res += 1
flag = 1
elif cur.val not in mydict:
flag = 0
cur = cur.next
return res
其他
1019. 鏈表中的下一個更大節點
- 用一個棧來保存當前未找到更大節點值的節點
- res用來保存返回的結果
- 如果遍歷到當前節點的值比棧頂的節點值還小或相等,把當前這個節點和它的下標保存到棧中
- 如果遍歷到當前節點的值比棧頂的節點值大,就while循環,把當前節點的值都保存到棧頂下標所在的res中去,然后把當前節點append到棧中
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def nextLargerNodes(self, head: ListNode) -> List[int]:
res, stack = [], []
index = 0
cur = head
while cur:
res.append(0)
while stack and cur.val > stack[-1][0].val:
node = stack.pop()
res[node[1]] = cur.val
stack.append([cur,index])
cur = cur.next
index += 1
return res
1367. 二叉樹中的列表
- 官方題解:遞歸
- 兩個函數,一個用來向下遞歸找到head的值與節點值相等的節點
- 另一個函數用來找當前的相等節點的下一個節點和head.next的值是否相等
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSubPath(self, head: ListNode, root: TreeNode) -> bool:
if not root:
return False
return self.helper(head, root) or self.isSubPath(head, root.left) or self.isSubPath(head, root.right)
def helper(self, head, root):
if not head:
return True
if not root:
return False
if head.val != root.val:
return False
return self.helper(head.next, root.left) or self.helper(head.next, root.right)
1171. 從鏈表中刪去總和值為零的連續節點
- 定義一個字典,遍歷兩次鏈表
- 遍歷的時候維護一個sum
- 第一次遍歷的時候,sum每遇到一個節點就加上這個節點的值,然后把sum作為key,當前的節點作為value保存在字典中,這樣相同sum的結點,在前面出現的就會被后面出現的覆蓋掉
-
第二次遍歷的時候,依然維護這個sum,當前節點的下一個節點就是字典中sum對應的節點的下一個節點
第一次遍歷:
image.png
第二次遍歷:
image.png
image.png
image.png
image.png
image.png
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeZeroSumSublists(self, head: ListNode) -> ListNode:
mydict = {}
mysum = 0
newhead = ListNode(0)
cur = newhead
newhead.next = head
while cur:
mysum += cur.val
mydict[mysum] = cur
cur = cur.next
mysum = 0
cur = newhead
while cur:
mysum += cur.val
cur.next = mydict[mysum].next
cur = cur.next
return newhead.next
138. 復制帶隨機指針的鏈表
同
劍指 Offer 35. 復雜鏈表的復制
- 使用字典+遍歷
- 第一次遍歷:使用字典node_to_index,遍歷鏈表,num由0開始,目的是把原來鏈表的每個節點作為key,num作為value保存在字典中。
- 例如[[7,null],[13,0],[11,4],[10,2],[1,0]]
-
字典中存儲的是:{[節點“7”:0],[節點“13”:1],[節點“11”:2],[節點“10”:3],[節點“1”:4]}
image.png
-
第二次遍歷:這次每個節點的index我們都知道了,第二次用字典index_to_random_index,把每個節點的index作為key,把這個節點的random的index作為value,保存在index_to_random_index字典中,random節點可以訪問到,就可以用這個節點在第一次遍歷得到的字典中取到這個random節點的index
image.png - 第三次遍歷:同時遍歷原來的鏈表和新建一個新的頭節點,用原來鏈表的值建一個新的鏈表。
-
第四次遍歷:新建一個字典index_to_newnode,把節點的下標作為key,節點作為value保存到數組中。
image.png -
第五次遍歷:把新鏈表的每個節點的random添加進去,因為知道當前節點的下標,知道每個下標對應的random的下標,也知道每個下標對應的新鏈表的節點
image.png
image.png
image.png
image.png
image.png - 代碼實現的時候,有些循環合并了,所以只循環了三次:
"""
# Definition for a Node.
class Node:
def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
self.val = int(x)
self.next = next
self.random = random
"""
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head:
return None
newhead = Node(0)
cur = newhead
tmp = head
num = 0
mydict_node_to_index = {}
index_to_mynewnode = {}
while tmp:
cur.next = Node(tmp.val)
cur = cur.next
mydict_node_to_index[tmp] = num
index_to_mynewnode[num] = cur
num += 1
tmp = tmp.next
index_to_random_index = {}
tmp = head
while tmp:
index_to_random_index[mydict_node_to_index[tmp]] = None if not tmp.random else mydict_node_to_index[tmp.random]
tmp = tmp.next
cur = newhead.next
num = 0
while cur:
if index_to_random_index[num] is not None:
cur.random = index_to_mynewnode[index_to_random_index[num]]
cur = cur.next
num += 1
return newhead.next
一樣的寫法:
"""
# Definition for a Node.
class Node:
def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
self.val = int(x)
self.next = next
self.random = random
"""
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head:
return None
newhead = Node(0)
cur = newhead
tmp = head
node_to_index = {}
index_to_newhead = {}
num = 0
while tmp:
cur.next = Node(tmp.val)
cur = cur.next
index_to_newhead[num] = cur
node_to_index[tmp] = num
num += 1
tmp = tmp.next
index_to_random_index = {}
num = 0
tmp = head
while tmp:
index_to_random_index[num] = node_to_index[tmp.random] if tmp.random is not None else None
tmp = tmp.next
num += 1
cur = newhead.next
num = 0
while cur:
if index_to_random_index[num] is not None:
cur.random = index_to_newhead[index_to_random_index[num]]
cur = cur.next
num += 1
return newhead.next
430. 扁平化多級雙向鏈表
具體實現看代碼吧。
注意1是要把原來的child置為空,2是prev要有指向。
要是寫完發現節點的順序是對的,但是不是一個有效的雙向鏈表估計就是注意1和2的問題,用循環打印一下當前節點的值和當前節點的prev值看看是不是有沒連上的。
"""
# Definition for a Node.
class Node:
def __init__(self, val, prev, next, child):
self.val = val
self.prev = prev
self.next = next
self.child = child
"""
class Solution:
def flatten(self, head: 'Node') -> 'Node':
if not head:
return head
cur = head
while cur:
if cur.child:
self.helper(cur)
cur = cur.next
return head
def helper(self, node):
right = node.next
node.next = node.child
node.child.prev = node
node.child = None
while node.next:
if node.child:
self.helper(node)
node = node.next
node.next = right
if right:
right.prev = node
return node
147. 對鏈表進行插入排序
- 新建頭節點
- 維護一個tail,一開始指向新的頭節點
- 遍歷鏈表,如果當前的節點比tail節點的值大,直接插在tail節點后,把tial指向這個新插入的節點,記得tail的next要指向空,要不就無限循環了。。
- 如果當前節點值比tail小,那么新建一個tmp指向頭,找到當前節點應該插入的為止,把它插進去
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def insertionSortList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
newhead = ListNode(float('-inf'))
tail = newhead
cur = head
nex = cur
while cur:
nex = nex.next
if cur.val < tail.val:
tmp = newhead
while cur.val > tmp.val and cur.val > tmp.next.val:
tmp = tmp.next
cur.next = tmp.next
tmp.next = cur
else:
tail.next = cur
tail = tail.next
tail.next = None
cur = nex
return newhead.next
困難
23. 合并K個排序鏈表
解法一:
- 用小根堆把所有節點的值都保存起來,然后用這些值重新建一個新鏈表
# 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:
heap = []
for i in lists:
while i:
heapq.heappush(heap,i.val)
i = i.next
head = ListNode(0)
cur = head
while heap:
cur.next = ListNode(heap[0])
heapq.heappop(heap)
cur = cur.next
return head.next
其他解法待更新~
25. K 個一組翻轉鏈表
- 用pre來標志之前已經翻轉過的鏈表尾
- cur表示當前要遍歷的節點
- 定義一個newhead做新的鏈表頭節點,把head賦給newhead的next
- 然后開始遍歷,每到一個新的cur,把tail指向這個cur,然后tail向下遍歷,找到要翻轉的子鏈表的尾
- 使用helper函數,把cur和tail傳給這個函數
- helper函數的實現:
- 把tail的next作為pre保存起來
- 當tail和pre不相同時,遍歷繼續
- 遍歷的內容是從傳遞過來的cur開始把cur傳給tmp,把tmp的next作為nex保存起來,再把tmp的next指向pre,這樣就完成了一個節點的翻轉,然后把pre指向當前節點,tmp指向nex,nex指向tmp.next
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
newhead = ListNode(0)
newhead.next = head
pre = newhead
cur = head
while cur:
tail = cur
for i in range(1, k):
tail = tail.next
if not tail:
return newhead.next
nex = tail.next
cur, tail = self.helper(cur, tail)
pre.next = cur
tail.next = nex
pre = tail
cur = tail.next
return newhead.next
def helper(self, head, tail):
pre = tail.next
tmp = head
while pre != tail:
nex = tmp.next
tmp.next = pre
pre = tmp
tmp = nex
return tail, head