链表中环的入口结点(剑指offer)Floyd+O(1)

链表中环的入口结点
  • 参与人数:609时间限制:1秒空间限制:32768K
  • 通过比例:24.75%
  • 最佳记录:0 ms|8552K(来自  白云和黑土)

题目描述

一个链表中包含环,请找出该链表的环的入口结点。

题目链接:http://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

 

思路:找环的入口结点,那么必须先存在环。判断是否存在环的话,可以用Folder判圈法!

所谓“Floyd判圈法”,就是假设有两个小孩子在一个圆圈跑道上赛跑,同时出发,但其中一个小孩的速度是另一个的两倍,所以跑得快的小孩将“追上”跑得慢的小孩(已经超过n圈了)。当超过的那一刻,可以肯定的是,此时快的小孩已经至少跑了1圈以上了,也就是“经过了一个循环”。于是我们可以根据两个小孩是否会相遇来判断“这条路”是否构成一个圈,因为如果不构成一个圈,是一个无限长的直线的话,这两个孩子就永远不会相遇。

do  
{  
   k1 = next(n, k1); // 小孩1  
   k2 = next(n, k2); // 小孩2,第一步  
   if(k2 > ans) ans = k2;  
     k2 = next(n, k2); // 小孩2,第二步  
   if(k2 > ans) ans = k2;  
}  
while(k1 != k2);   // 追上以后才停止


 

有了这个思路,那么这道题就可以解决了,当有圈的时候在以相遇的结点出发,统计回到这个点走了多少步(n步),即圈的大小(为n),然后再利用快慢指针,先让快指针先走n步,接着慢指针和快指针一起走,当他们相遇的时候就是圈的入口结点;

 

类似于找链表的倒数第几个点,思路是一样的。

参考:http://blog.csdn.net/u010579068/article/details/48272185

 

本题的代码:

 

#include<stdio.h>
#include<iostream>
using namespace std;

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};

class Solution {
public:
    bool JudgeList(ListNode *pp,int &n)//判断是否成环
    {
        bool bo=false;
        ListNode *p,*q,*r;
        p=new ListNode(NULL);
        q=new ListNode(NULL);
        p->next=pp;
        q->next=pp;
        while(q->next->next)
        {
            p=p->next;
            q=q->next->next;
            if(p==q) {r=p;bo=true;break;}
        }
        if(!bo) return false;
        else
        {
//           printf("p=====%d\n",p->val);
            n=1;
            p=p->next;
            do{
                n++;
                p=p->next;
            }while(r!=p);
            return true;
        }
    }
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(!pHead||!pHead->next) return NULL;

        ListNode *p,*q;
        int n=0;
        p=new ListNode(NULL);
        q=new ListNode(NULL);
        if(JudgeList(pHead,n))//有环
        {
    //        printf("%d\n",n);

            int k=0;
            p->next=pHead;
            q->next=pHead;
            while(p->next)
            {
                p=p->next;
                k++;
                if(k>n)
                {
                    q=q->next;
                }
                if(p==q) {return q;}
            }
        }
        else return NULL;
    }
    ListNode* CreatList(ListNode *pHead,int n,int k)
    {
        if(n==0) return NULL;
        ListNode *p,*q,*r;
        pHead=new ListNode(NULL);
        p=pHead;
        if(k==1) r=pHead;
        cin>>p->val;
        int x,i=2;
        while(i<=n)
        {
            cin>>x;
            q=new ListNode(x);
            p->next=q;
            p=q;
            if(i==k) r=q;
            i++;
        }
 //       printf("r===%d\n",r->val);
        p->next=r;
        return pHead;
    }

};
int main()
{
    //n表示链表的长度,k表示链表的入口结点;
    int n,k;
    Solution so;
    ListNode *L;
    cin>>n>>k;
    L=so.CreatList(L,n,k);
    ListNode *ans=so.EntryNodeOfLoop(L);
    printf("%d\n",ans->val);
    return 0;
}

 

你可能感兴趣的:(链表,剑指offer,Folder判圈,成环问题)