subject
If a linked list contains a ring, the first node entering the ring from the chain header node in the direction of the next pointer is the ring entry node.
Now that the head node head is known, locate the entry node.
Idea:
Differential method - make n turns when the fast and slow pointers meet. Adjust the starting position so that they just meet at the entrance node.
Steps:
1. Locate the "meeting point" - the fast and slow pointer starts from the beginning at the same time to locate the ring meeting point (this action can also be used to judge whether the linked list has a ring and return a node in the ring, which is very useful!)
2.P1 starts from the head node, P2 starts from the meeting point, and then meets again, which is the entry node
Example (from q22 in Chapter 4 of sword finger Offer):
Given the pointer of the chain header node in the figure, the returned content should be the pointer of entry node 3
First create the example list:
'''Define linked list nodes''' class ListNode(): def __init__(self, item): self.item = item self.next = None '''Create sample linked list''' arr = [1,2,3,4,5,6] n = len(arr) head = ListNode(arr[0]) cur = head for i in range(1,n): node = ListNode(arr[i]) cur.next = node cur = cur.next '''Connect the ring''' tail = head for i in range(0,5): tail = tail.next entry = head for i in range(0,2): entry = entry.next tail.next = entry
After creating it, check the contents of the linked list to see if it is connected correctly
'''Check circular linked list''' arr_check = [] cur = head tag = 0 while(cur != None)&(tag<15): arr_check.append(cur.item) cur = cur.next tag+=1 print(arr_check)
The result output is as follows (cyclic output from the position of the ring, i.e. 1 2 3 4 5 6 - > 3 4 5 6 - > 3 4 5 6 - > 3...):
[1, 2, 3, 4, 5, 6, 3, 4, 5, 6, 3, 4, 5, 6, 3]
Implement search
The solution class contains two functions:
-locateMeetNode() is responsible for finding the "encounter node" and judging whether the linked list has a ring
-findEntry() is responsible for pushing out the entry node by using the encounter node
class Solution(): '''Step 1 locate meet node - fast vs slow''' def locateMeetNode(self, head: ListNode) -> ListNode: if (head == None)|(head.next == None): print('List chain not exist or contains 1 node only.') return None else: slow = head.next fast = slow.next while(fast != None)&(slow != None): if(fast == slow): return slow slow = slow.next fast = fast.next if(fast != None): fast = fast.next '''if the loop ends without returning anything, then there is no circle in list chain''' print('This list chain contains no circle.') return None '''Step 2 start from meet node - meet again''' def findEntry(self, head: ListNode) -> ListNode: p1 = head p2 = self.locateMeetNode(head) if(p2 == None): print('No entry because there is no circle.') return None while(p1 != p2): p1 = p1.next p2 = p2.next return p1
Test code:
1. Check whether the meeting point is correct. According to the linked list of this question, it should be 5
s1 = Solution() meet = s1.locateMeetNode(head) meet.item
Result output: 5
2. Check whether the entry node is correct. According to the linked list, it should be 3
entry = s1.findEntry(h1) entry.item
Result output: 3
Reflection: stuck place
1. Instantiation of solution class s1=Solution() takes 15 minutes to find the reason and try to reconstruct the function for 15 minutes, which is about half an hour in total
2. Extreme cases that must be considered when using the double pointer method: head = = None, head Next = = None returns None directly
3. Double pointer loop loop control sequence: first compare the pointers, then walk, and then fast needle empty check + 1 step
4. Careless problem: typo writes the starting point of the fast pointer incorrectly, resulting in debugging for 10 minutes
In the follow-up practice, we should continue to consolidate the foundation and prevent careless problems, so as to reduce the debug time.