LeetCode Question 141-Circular Linked List I and LeetCode 142 Question-Circular Linked List II

1. Circular linked list I

Title description:

Given a linked list, determine whether there is a ring in the linked list.

If there is a node in the linked list that can be reached again by continuously tracking the next pointer, then there is a ring in the linked list. In order to represent the rings in a given linked list, we use the integer pos to indicate the position where the end of the linked list is connected to the linked list (the index starts from 0). If pos is -1, there are no rings in the linked list. Note: pos is not passed as a parameter, just to identify the actual situation of the linked list.

If there is a ring in the linked list, return true. Otherwise, it returns false.

Insert picture description here
Insert picture description here
The amount of code to solve the problem is very small, but it does not mean that it is very simple. The realization of this problem is not very difficult, but if you add a question:
Can you prove how fast pointers catch up with slow pointers?

Your hypothetical slow pointer moves one step at a time, and why does the fast pointer move two steps at a time? Can’t you take three or four steps? Can't you take n steps?
The answer is: No , you assume that slow takes one step each time, but each time fast takes three steps, then they all enter the ring with a difference of X steps, then each step they take will be reduced by 2 steps, and the rest is Step X-2, when X is an odd number, it is fine, but when it is an even number, they will stagger and fail to meet each other. The remaining fast takes four steps, and the n steps are similar. The best way to solve the problem is to take two steps fast, because this way the distance between them will be reduced by 1 step each time, and they will never be staggered. They will definitely want to encounter them, and the slow pointer will never go longer than the loop. The perimeter will be caught up by the quick pointer.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
*/
bool hasCycle(struct ListNode *head) {
    
    
    struct ListNode* fast = head,*slow = head;
    //因为你并不能确定这个链表一定是带环的,所以循环的条件还是要按照正常的思路来写的
    while(fast && fast->next)
    {
    
    
        //慢指针走的慢,快指针一次走两步走的快,如果有环,那么总会达到快指针追上了慢指针
        slow = slow->next;
        fast = fast->next->next;
        //他们都进入了环里,快指针追上了慢指针
        if(slow ==fast)
            return true;
    }
    return false;   
}

2. Circular Linked List II

Title description:
Given a linked list, return the first node where the linked list starts to enter the loop. If the linked list has no rings, null is returned.

In order to represent the rings in a given linked list, we use the integer pos to indicate the position where the end of the linked list is connected to the linked list (the index starts from 0). If pos is -1, there are no rings in the linked list. Note that pos is only used to identify the ring, and will not be passed to the function as a parameter.
Insert picture description here
Insert picture description here
There are two ways to solve the problem:
①It is troublesome to write, but the understanding is very simple: the slow pointer takes one step and the fast pointer takes two steps, then it will always meet in the ring, then that point is the meeting point, and then I let this ring from This intersection point is disconnected, one is the first head, and the other you set a new head (the next position of the disconnection point), then you let the two linked lists go, and you will find the intersection point, which is converted to The type of the original question (intersection of the linked list)

②It is simple to write, but it is troublesome to understand, and it also needs proof of formula.
Wrong problem-solving idea : the slow pointer cannot travel more than the circumference of the ring, so the length of the slow pointer must be the distance of L+X, and the distance of the fast pointer is L+X+C (where L It is the distance before entering the linked list, X represents the difference between entering the ring and meeting, and C represents the perimeter of the ring) 2*(L+X) = L+X+C, this is too one-sided to think.
Insert picture description here
When L is much larger than C, you will find that your fast has entered the ring very early, but your slow is still walking on top of L, then your fast is gone but there is more than one C more than slow .
Correct solution : Fast pointer: L + N C + X Then use this formula to deduce the final result 2 (L+X) = L + N*C + X Conclusion L=NC-X, you will find the wrong answer above It's just a case of the correct answer. The following steps are the same as the first problem-solving idea above. Define two heads, and then they will meet at the end of L. That is the intersection point.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    
    
    struct ListNode* slow = head,* fast = head;
    while(fast && fast->next)
    {
    
    
        //这一步是在最后进行测试用例不过的时候返回来判断发现的一个问题,如果你把if判断放在前面,就会一开始的快慢指针就是相等的,那么你一进入这个循环的时候就直接break了
            slow = slow->next;
            fast = fast->next->next; 
            //所以这里选择先进行走一步,然后判断,不然就会直接跳出来了
            if(slow == fast)
                break;
    }
    //上面的循环跳出来有两种可能,第一如果链表是带环的,那么一定以break跳出来,那个时候就找到了快慢指针的相遇点,第二种就是都遍历完了,fast都走到NULL的时候依旧没有找到两个相遇的点,说明这个链表是不带环的。
    //这段代码表示这个链表不带回环,当为奇数个的时候fast为NULL,偶数个的时候fast->next为NULL,但是不管哪种情况出现,都可以表示这是一个没有回环的链表
    if(fast == NULL || fast->next == NULL)
        return NULL;
    struct ListNode * meet = fast;
    while(head != meet)
    {
    
    
        head = head->next;
        meet = meet->next;
    }
    return meet;
}

Insert picture description here

Guess you like

Origin blog.csdn.net/MEANSWER/article/details/111866939