链表 寻找链表中环的起点

给定一个单链表,若该链表有环,返回环的起点,若没有,返回NULL

基本思路:

每遇到一个节点,计数器++ ,当遇到访问次数为2时,返回该节点,否则在循环结束前还没有找到,则返回NULL



class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(!pHead) 
            return null;
        map<ListNode*,int> flag;//统计节点访问次数
        while(pHead)
        {
            if(++flag[pHead]==2)
            return pHead;
            pHead=pHead->next;
        }
        return null;
        
    }
};

进阶思路:双指针思路,

  • 设置一快一慢双指针,初始化双指针指向起点
  • 每次快指针移动2步,慢指针移动1步
  • 若有环,则一定在环中相遇
  • 设置快指针到起点,2个指针每次移动1步,相遇时即为环起点 

证明:

慢指针速度为V  那么快指针速度为2V  第一次相遇,快指针先走了一圈 

  • Vt=L1+L2
  • 2Vt=L1+L2+L3+L2

2式子相减,得出L1=L3      那么将快指针放到起点开始每次移动1步,下次相遇一定发生在环起点位置

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        //链表不存在 或仅仅一个点的情况
        if(pHead==NULL || pHead->next==NULL)
            return NULL;
        //设置双指针(一快 一慢),如果存在环那么一定会在环内相交
        ListNode* fast=pHead;
        ListNode* slow=pHead;
        ListNode* point=NULL;
        while(fast->next->next!=NULL && slow->next!=NULL)
        {
            fast=fast->next->next;//快指针每次走2步
            slow=slow->next;//慢指针每次走1步
            if(fast==slow) //说明相交了
            {
                point=fast;
                break;
            }
        }
        if(point==NULL)//说明循环结束 还没有相交,也就是没有环
            return NULL;
        fast=pHead;//将快指针设为头部,速度和slow一致,相遇处即为环起点
        while(fast!=slow)
        {
            fast=fast->next;
            slow=slow->next;
        }
        return fast;

    }
};

猜你喜欢

转载自blog.csdn.net/qq_33369979/article/details/88533974