判断链表是否有环 Linked List Cycle, Linked List Cycle II

有感leetcode上的两个题:Linked List Cycle   和 

Linked List Cycle II

 

1. Given a linked list, determine if it has a cycle in it.

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

一开始用的set来做,即把已经访问过的节点放到set里,依次访问链表的各个节点,如果某个节点不在set中,将它加入到set,如果已经在了,则有环。而第一个已经在set中的节点,即为环的第一个节点。

stl的set用的是红黑树,unordered_set是用hash实现,所以后者会快一些。

如果用这个方法的话,两道题代码很通用。。。

class Solution {
public:
    bool hasCycle(ListNode *head) {
		set<int> s;
		if(head==NULL)
			return false;
		ListNode* t = head;
		ListNode* n = NULL;		
		n = new ListNode((int)head);
		t = t->next;
		while(1){
			if(t==NULL)
				return false;
			else{
				set<int>::iterator it = s.find((int)t);
				if(it!=s.end())
					return true;
				s.insert((int)t);
			}
			t = t->next;

		}
    }
};

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        set<int> s;
		if(head==NULL)
			return NULL;
		ListNode* t = head;
		ListNode* n = NULL;		
	    s.insert((int)head);
		t = t->next;
		while(1){
			if(t==NULL)
				return NULL;
			else{
				set<int>::iterator it = s.find((int)t);
				if(it!=s.end())
					return t;
				s.insert((int)t);
			}
			t = t->next;
		}
    }
};


这个题目其实是典型的快慢指针的问题,一个快指针一个慢指针,如果慢指针能追上快指针,则有环,否则,无。这个是解决第一个题的方法,贴代码:

class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head==NULL)
            return false;
		ListNode* two = head;
		ListNode* one = head;
		while(1){
		    one = one->next;
		    two = two->next;
		    if(one ==NULL || two==NULL)
		        return false;
		    two = two->next;
		    if(one ==NULL || two==NULL)
		        return false;
		    if(one==two)
		        return true;
		}
		return true;
    }
};


有了快慢指针以后,可以判断出有没有环,那么,怎么去找出环的第一个节点?

这是一个著名的龟兔赛跑问题。

假设这个链表的非环的部分长度为L,环的长度为R,相遇的位置在环的第K个节点,则有:

T = L+K+m*R

2*T = L+K+n*R

带入T则有 (n-2*m)*R=L+K

由于n-2*m 是整数,所以得出(L+K)%R=0,即L=x*R-K,则有:

此时另一个节点从head开始单步遍历,同时步长为1的节点也开始单步遍历,直到二者相遇时,即是环的第一个节点。

 class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head==NULL)
            return NULL;
        ListNode* one = head;
        ListNode* two = head;
        while(1){
            one = one->next;
            two = two->next;
            if(one==NULL || two==NULL)
                return NULL;
            two = two->next;
            if(two==NULL)
                return NULL;
            if(two==one)
                break;
        }
        two = head;
        while(two!=one){
            one = one->next;
            two = two->next;
        }
        return one;
    }
};

精妙呀。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值