Linked list - find entry ring node

Posted by Vinze on Sun, 09 Jan 2022 09:54:56 +0100

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.

Topics: data structure linked list