判断一个链表是否有环,如果有环返回环开始的结点指针

LeetCode OJ :Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Follow up:Can you solve it without using extra space?

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if((head == NULL) || (head->next == NULL))
            return NULL;
        ListNode *p, *q;
        p = q = head;
        
        p = p->next;
        q = q->next->next;
    
        //指针追击问题
        while((q != NULL) && (q->next != NULL) && (p != q))
        {
            p = p->next;
            q = q->next->next;
        }
        if((q == NULL) || (q->next == NULL))
            return NULL;
        else if(p == q)     //链表肯定存在环
        {
            int flag = 0;
            ListNode *r, *first;
            r = head;
         
            if((r == p) || (r == q))    //只包含头结点的环
                return r;
                
            if(p->next == q->next->next)//只包含尾结点的环
                return p;
            
            while((p != r) && (q != r))
            {
                p = p->next;
                q = q->next->next;
                
                while(p != q)
                {
                    if((p == r) || (q == r))
                        return r;
            
                    p = p->next;
                    q = q->next->next;
                }
                r = r->next;
                
                if((r == p) || (r == q))    
                    return r;
            }
           
        }
        
    }
};

看到一个更牛叉的解法:这实际上是一个经典的龟兔赛跑问题。

假设:

  • x:环开始的索引结点
  • y:环的长度
  • 兔的赛跑速度是龟的两倍
  • 这样兔肯定在环内的某一点上追上龟,假设这一点为m
这样如果设龟走过的总路程为:x+ky+m,兔走过的总路程为:x+ty+m。则有:

x+ty+m = 2(x+ky+m)
故有:x+m = (t-2k)y。所以(x+m)mod y = 0,所以有如下方法:

让快指针停在两指针相遇的点,然后让慢指针回到头指针的位置,两个指针同时出发,每次走一步。

当慢指针走到环的第一个结点处(即走了x步),此时快指针距离环的第一个结点的位置为:x+m,即也在环的第一个结点处。所以此时两个指针又相遇了。

这样就可以判定环的第一个结点的位置了,即,两指针相遇的位置!

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // IMPORTANT: Please reset any member data you declared, as
        // the same Solution instance will be reused for each test case.
        ListNode* slow = head;
        ListNode* fast = head;
        do{
            if( !slow || !fast ) return NULL;
            slow = slow->next;
            fast = fast->next;
            if( fast ) fast = fast->next;
            else return NULL;
        }while( slow != fast );
        slow = head;
        while( slow != fast ){
            slow = slow->next;
            fast = fast->next;
        }
        return slow;
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值