目錄
206. 反轉鏈表
https://leetcode-cn.com/problems/reverse-linked-list/
反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
進階:
你可以迭代或遞歸地反轉鏈表。你能否用兩種方法解決這道題?
題解
一:迭代,定義了三個指針,通過挪動三個指針來完成題目。
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
pre_node, cur_node = None, head
while cur_node:
next_node = cur_node.next
cur_node.next = pre_node
pre_node = cur_node
cur_node = next_node
return pre_node
二:迭代,copy官方題解,https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/,
遞歸版本稍微複雜一些,其關鍵在於反向工作。假設列表的其餘部分已經被反轉,現在我該如何反轉它前面的部分?
假設列表爲:
若從節點
到
已經被反轉,而我們正處於
。
我們希望
的下一個節點指向
。所以
,也即
要小心的是的下一個必須指向 Ø 。如果你忽略了這一點,你的鏈表中可能會產生循環。如果使用大小爲 2 的鏈表測試代碼,則可能會捕獲此錯誤。
函數reverseList返回的是翻轉後的鏈表的頭節點,其中head.next=None,是必須的,因爲翻轉後,原頭節點的next是空。
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
next_node = head.next
p = self.reverseList(head.next)
next_node.next = head
head.next = None
return p
92. 反轉鏈表 II
https://leetcode-cn.com/problems/reverse-linked-list-ii/
反轉從位置 m 到 n 的鏈表。請使用一趟掃描完成反轉。
說明:1 ≤ m ≤ n ≤ 鏈表長度。
示例:輸入: 1->2->3->4->5->NULL, m = 2, n = 4,輸出: 1->4->3->2->5->NULL。
題解
一:借鑑206反轉鏈表的思路,其中reverse函數是翻轉m到n之間的鏈表,並返回翻轉之後的頭節點pre(4)以及原鏈表的下一個節點cur(5,即無需翻轉的第一個節點),主體結構的cur(2)是第一個要翻轉的節點(翻轉之後是新鏈表的尾節點),pre(1)是最後一個無需翻轉的節點。
class Solution(object):
def reverseBetween(self, head, m, n):
"""
:type head: ListNode
:type m: int
:type n: int
:rtype: ListNode
"""
def reverse(node):
num = n - m + 1
cnt = 1
pre, cur = None, node
while cnt <= num:
next = cur.next
cur.next = pre
pre = cur
cur = next
cnt += 1
return pre, cur
before_head = ListNode(0)
before_head.next = head
pre, cur = before_head, head
cnt = 1
while cnt < m:
pre = cur
cur = cur.next
cnt += 1
before, next = reverse(cur)
pre.next, cur.next = before, next
return before_head.next
83. 刪除排序鏈表中的重複元素
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/
給定一個排序鏈表,刪除所有重複的元素,使得每個元素只出現一次。
示例 1:輸入: 1->1->2,輸出: 1->2
示例 2:輸入: 1->1->2->3->3,輸出: 1->2->3
題解
一:下一個元素與當前重複的元素,讓該指針指向下一個元素的下一個(即跳掉下一個元素),若不重複,比較後續元素。因爲每個元素只出現一次,頭節點就依然會是頭節點,不會被刪除。與下一題的區別,最後一個節點的next肯定爲None,不要單獨處理。
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
cur = head
while cur.next:
next = cur.next
if cur.val == next.val:
cur.next = next.next
else:
cur = cur.next
return head
82. 刪除排序鏈表中的重複元素 II
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/
給定一個排序鏈表,刪除所有含有重複數字的節點,只保留原始鏈表中 沒有重複出現 的數字。
示例 1:輸入: 1->2->3->3->4->4->5,輸出: 1->2->5
示例 2:輸入: 1->1->1->2->3,輸出: 2->3
題解
一:這邊與上一題的區別,頭節點可能會被刪掉,故添加一個虛擬節點,符合要求的鏈表的最後一個節點是pre,考慮當前節點,他若和前一個節點或者後一個節點相等,都要跳掉,若不相等,則將pre指向該節點,要注意每時每刻符合要求的最後一個節點都是pre,故遍歷完畢,要讓pre.next=None。
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
before_head = ListNode(head.val - 1)
before_head.next = head
pre, cur, val = before_head, head, before_head.val
while cur:
next = cur.next
if cur.val == val or (next and next.val == cur.val):
val = cur.val
cur = next
else:
pre.next = cur
pre = cur
cur = next
pre.next = None
return before_head.next
86. 分隔鏈表
https://leetcode-cn.com/problems/partition-list/
給定一個鏈表和一個特定值 x,對鏈表進行分隔,使得所有小於 x 的節點都在大於或等於 x 的節點之前。你應當保留兩個分區中每個節點的初始相對位置。
示例:輸入: head = 1->4->3->2->5->2, x = 3,輸出: 1->2->2->4->3->5
題解
一:創建兩個鏈表(小於是一個,大於等於是一個,在把這倆鏈表合併成一個),小trick:初始化爲兩個啞 ListNode,這樣可以避免判斷是否是第一個節點(小於、大於等於的),注意事項:要注意大於等於x的那個鏈表的尾節點的next要初始化爲空,不然他有可能會指向別的節點,從而形成環。
class Solution(object):
def partition(self, head, x):
"""
:type head: ListNode
:type x: int
:rtype: ListNode
"""
less_head, great_head = ListNode(x), ListNode(x)
cur, cur_less, cur_great = head, less_head, great_head
while cur:
next = cur.next
if cur.val < x:
cur_less.next = cur
cur_less = cur
else:
cur_great.next = cur
cur_great = cur
cur = next
cur_great.next = None
cur_less.next = great_head.next
return less_head.next
328. 奇偶鏈表
https://leetcode-cn.com/problems/odd-even-linked-list/
給定一個單鏈表,把所有的奇數節點和偶數節點分別排在一起。請注意,這裏的奇數節點和偶數節點指的是節點編號的奇偶性,而不是節點的值的奇偶性。請嘗試使用原地算法完成。你的算法的空間複雜度應爲 O(1),時間複雜度應爲 O(nodes),nodes 爲節點總數。
示例 1:輸入: 1->2->3->4->5->NULL,輸出: 1->3->5->2->4->NULL
示例 2:輸入: 2->1->3->5->6->4->7->NULL ,輸出: 2->3->6->7->1->5->4->NULL
說明:應當保持奇數節點和偶數節點的相對順序。鏈表的第一個節點視爲奇數節點,第二個節點視爲偶數節點,以此類推。
題解
一:還是兩個鏈表,第一個奇數節點,第二個偶數節點,做這類題目注意把握好循環進行下去的條件,即用那個指針進行判斷,可以用例子來看看是否有問題,例如[1,2,3,4]和[1,2,3,4,5]。
這邊要注意,循環體中的判斷第一處if even_cur.next是爲了確保even_cur.next.next這句話的正確性,第二處if odd_cur.next:是爲了確保odd_cur不爲None,保證odd_cur.next = even_head的正確性。
class Solution(object):
def oddEvenList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
odd_head, even_head = head, head.next
odd_cur, even_cur = odd_head, even_head
while even_cur:
odd_cur.next = even_cur.next
if even_cur.next:
even_cur.next = even_cur.next.next
if odd_cur.next:
odd_cur = odd_cur.next
even_cur = even_cur.next
odd_cur.next = even_head
return odd_head
精簡一點,在循環的時候一起判斷,不再循環體中單獨判斷。
class Solution(object):
def oddEvenList(self, head):
if not head or not head.next:
return head
odd_head, even_head = head, head.next
odd_cur, even_cur = odd_head, even_head
while even_cur and even_cur.next:
odd_cur.next = even_cur.next
even_cur.next = even_cur.next.next
odd_cur = odd_cur.next
even_cur = even_cur.next
odd_cur.next = even_head
return odd_head
2. 兩數相加
https://leetcode-cn.com/problems/add-two-numbers/
給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
示例:輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4),輸出:7 -> 0 -> 8,原因:342 + 465 = 807
題解
一:沒啥注意的,依舊是關注指針是否爲None的問題(即我們是否用了None的next,也即合法性)。另外,所有的數加完之後,要判斷是否有進位,若有還要創建一個節點以對應該進位。
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
before_head = ListNode(0)
cur, cur_1, cur_2, carry = before_head, l1, l2, 0
while cur_1 or cur_2:
val = carry
if cur_1:
val += cur_1.val
cur_1 = cur_1.next
if cur_2:
val += cur_2.val
cur_2 = cur_2.next
carry = val // 10
val = val % 10
cur.next = ListNode(val)
cur = cur.next
if carry:
cur.next = ListNode(carry)
return before_head.next
445. 兩數相加 II
https://leetcode-cn.com/problems/add-two-numbers-ii/
給你兩個 非空 鏈表來代表兩個非負整數。數字最高位位於鏈表開始位置。它們的每個節點只存儲一位數字。將這兩數相加會返回一個新的鏈表。你可以假設除了數字 0 之外,這兩個數字都不會以零開頭。
進階:如果輸入鏈表不能修改該如何處理?換句話說,你不能對列表中的節點進行翻轉。
示例:輸入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4),輸出:7 -> 8 -> 0 -> 7
題解
一:反轉鏈表,再用題2的方法,得到結果之後繼續反轉
二:藉助數據結構,將鏈表中的數據存儲下來。這邊用的列表。
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
rec1, rec2, rec = [], [], []
self._abstract_num(l1, rec1)
self._abstract_num(l2, rec2)
self._sum(rec1, rec2, rec)
before_head = ListNode(0)
cur = before_head
for i in range(len(rec)-1, -1, -1):
val = rec[i]
cur.next = ListNode(val)
cur = cur.next
return before_head.next
def _abstract_num(self, l, rec):
cur = l
while cur:
rec.append(cur.val)
cur = cur.next
def _sum(self, rec1, rec2, rec):
i, j, carry = len(rec1)-1, len(rec2)-1, 0
while i >= 0 or j >= 0:
val = carry
if i >= 0:
val += rec1[i]
i -= 1
if j >= 0:
val += rec2[j]
j -= 1
carry = val // 10
val = val % 10
rec.append(val)
if carry:
rec.append(carry)
三:copy官方題解,https://leetcode-cn.com/problems/add-two-numbers-ii/,借用棧的結構後進先出,list的append和pop可做到,然後最後倒着把鏈表連起來
class Solution(object):
def addTwoNumbers(self, l1, l2):
rec1, rec2 = [], []
self._abstract_num(l1, rec1)
self._abstract_num(l2, rec2)
ans, carry = None, 0
while rec1 or rec2 and carry != 0:
x = rec1.pop() if rec1 else 0
y = rec2.pop() if rec2 else 0
val = carry + x + y
carry = val // 10
val = val % 10
cur = ListNode(val)
cur.next = ans
ans = cur
return ans
def _abstract_num(self, l, rec):
while l:
rec.append(l.val)
l = l.next
203. 移除鏈表元素
https://leetcode-cn.com/problems/remove-linked-list-elements/
刪除鏈表中等於給定值 val 的所有節點。
示例:輸入: 1->2->6->3->4->5->6, val = 6, 輸出: 1->2->3->4->5
題解
一:跳過就👌啦,要注意這句話pre.next = None,否則若最後一個元素應該被刪除,缺少這句話刪不掉,虛擬頭節點一直就是鏈表題目的小trick。
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
before_head = ListNode(0)
pre, cur = before_head, head
while cur:
if cur.val != val:
pre.next = cur
pre = cur
cur = cur.next
pre.next = None
return before_head.next
21. 合併兩個有序鏈表
將兩個升序鏈表合併爲一個新的升序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。
示例:輸入:1->2->4, 1->3->4,輸出:1->1->2->3->4->4
題解
一:不改變原先兩鏈表的結構
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
before_head = ListNode(0)
pre = before_head
while l1 or l2:
if not l1:
pre.next = ListNode(l2.val)
l2 = l2.next
elif not l2:
pre.next = ListNode(l1.val)
l1 = l1.next
elif l1.val < l2.val:
pre.next = ListNode(l1.val)
l1 = l1.next
else:
pre.next = ListNode(l2.val)
l2 = l2.next
pre = pre.next
return before_head.next
二:可以改變原先鏈表結構
class Solution(object):
def mergeTwoLists(self, l1, l2):
before_head = ListNode(0)
pre = before_head
while l1 and l2:
if l1.val < l2.val:
pre.next = l1
l1 = l1.next
else:
pre.next = l2
l2 = l2.next
pre = pre.next
pre.next = l1 if l1 else l2
return before_head.next