一、快慢指針的概念
快慢指針中的快慢指的是移動的步長,即每次向前移動速度的快慢。例如可以讓快指針每次沿鏈表向前移動2次,慢指針每次向前移動1次。
如果我們要在上圖鏈表中 刪除value爲10的節點,只需要設置兩個指針,每一次移動後,快指針都會比慢指針多走一個節點,這就能形成一個指針間的差值,通過這個差值,來斷開或者鏈接指針域,從而達到需要的結果。
二、快慢指針的應用
2.1 找中間值
思路:
設一個快指針 fast,設一個慢指針slow,假定快指針每次移動速度是慢指針的兩倍,當快指針到達尾部節點指向None時,慢指針則處於鏈表的中間節點,從而確定中間節點的值。
圖示:
slow與fast指針都指向鏈表第一個節點,然後slow每次移動一個指針,fast每次移動兩個指針。
代碼示例:
class ListNode:
def __init__(self, x, next=None):
self.val = x
self.next = next
class Solution:
def deleteNode(self, head: ListNode):
slow = head # 慢指針
fast = head # 快指針
while fast and fast.next:
slow = slow.next
fast = fast.next.next
print(slow.val)
if __name__ == '__main__':
a = ListNode(14, ListNode(23, ListNode(10, ListNode(35, ListNode(56, ListNode(59,ListNode(12,)))))))
obj = Solution()
Node = obj.deleteNode(a)
# 結果爲 35
2.2 刪除倒數第n個節點
思路:
1、刪除倒數第n個節點,意味着需要獲得 n-1的指針域以及n的指針域。
2、設置快慢兩個指針,先讓快指針先走n+1步,然後再和慢指針一起走,當快指針爲None時,慢指針剛好停留在 n-1的位置。
圖示:
代碼實例:
# 快慢指針
class ListNode:
def __init__(self, x, next=None):
self.val = x
self.next = next
class Solution:
def kthToLast(self, head: ListNode, k: int) -> int:
slow = head # 慢指針
fast = head # 快指針
while k+1 > 0:
fast = fast.next
k -= 1
while fast.next is not None:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
while head is not None:
print(head.val)
head = head.next
if __name__ == '__main__':
a = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5,)))))
obj = Solution()
Node = obj.kthToLast(a, 2)
# 結果爲 1,2,4,5
2.3 判斷是否爲環狀鏈表
思路:
快慢指針中,因爲每一次移動後,快指針都會比慢指針多走一個節點,所以他們之間在進入環狀鏈表後,不論相隔多少個節點,慢指針總會被快指針趕上並且重合,此時就可以判斷必定有環。
圖示:
如果fast指針遍歷出None,則說明沒有環。
當slow指針和falst指針相同,則說明環有節點。
代碼示例:
class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
def findbeginofloop(head):
slow = head # 慢指針
fast = head # 快指針
if head is None: # 判斷鏈表是否爲空
return head
while fast.next != None and fast.next.next != None: # fastPtr的下一個節點和下下個節點都不爲空
slow = slow.next
fast = fast.next.next
if slow == fast: # 兩個指針相遇存在環結構
print("存在環結構")
break
if __name__ == "__main__":
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node2
findbeginofloop(node1)