环形链表——双指针

原题在这里

概述题意:

  给定一个可能有环的链表,如果有环则返回第一个环节点,否则null

低配hash处理:

class Solution
{
    map<ListNode *, int> mp;

public:
    ListNode *detectCycle(ListNode *head)
    {
        if (!head || mp[head] == 1)
            return head;
        mp[head] = 1;
        return detectCycle(head->next);
    }
};
map or set

高配双指针:

class Solution
{
public:
    ListNode *detectCycle(ListNode *head)
    {
        ListNode *p = head, *q = head;
        while (p != nullptr)
        {
            q = q->next;
            if (p->next == nullptr)
                return nullptr;
            p = p->next->next;
            if (p == q)
            {
                //重新走一遍
                p = head;
                while (p != q)
                {
                    p = p->next;
                    q = q->next;
                }
                return p;
            }
        }
        return nullptr;
    }
};

analyse:

参考:https://leetcode-cn.com/problems/linked-list-cycle-ii/solution/linked-list-cycle-ii-kuai-man-zhi-zhen-shuang-zhi-/

大概:

  s快=s慢+n*b,s快=s慢*2,故得:s慢=n*b

如果有环,快指针与慢指针相遇时候,快指针一定比慢指针多走n倍环的长度b,又有快指针路径是慢指针两倍,所得慢指针当前路径为n倍环长度。

继续:

  从此点开始,用两指针分别从头和快慢指针相遇节点开始走,相遇的节点即为入环节点。

  也即s1=0,s2=n*b,那么走非环路径a后即有,s1=a,s2=a+n*b,两者相遇在入环节点。

code:

 

struct ListNode
{
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
class Solution
{
public:
    ListNode *detectCycle(ListNode *head)
    {
        ListNode *p = head, *q = head;
        while (p != nullptr)
        {
            q = q->next;
            if (p->next == nullptr)
                return nullptr;
            p = p->next->next;
            if (p == q)
            {
                //重新走一遍
                p = head;
                while (p != q)
                {
                    p = p->next;
                    q = q->next;
                }
                return p;
            }
        }
        return nullptr;
    }
};

 

 

 

【Over】

posted @ 2022-03-28 11:08  Renhr  阅读(33)  评论(0)    收藏  举报