Given a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space?
/**
*
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
// 时间复杂度O(N) 空间复杂度O(N)
public class Solution {
public boolean hasCycle(ListNode head) {
HashSet<ListNode> set = new HashSet<ListNode>();
if (head == null || head.next == null) {
return false;
}
// 利用额外的set的无重复特性来进行判断
while (head != null) {
if (!set.add(head)) {
return true;
}
head = head.next;
}
return false;
}
}
//时间复杂度O(N) 空间复杂度O(1)
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null){
return false;
}
ListNode p = head;
ListNode q = head;
while(q.next != null && q.next.next != null){
p = p.next;
q = q.next.next;
if(p == q) {
return true;
}
}
return false;
}
}
在第一个方法中:
利用set的无重复的特性,以作为循环里面的结束判断标准。
重复将每一个节点放置到set中,不断检测在set中是否有重复的节点,如果有的话那么这个链表中就有环,如果直到最后循环到了null,那么这个链表则没有环。
在第二个方法中:
这个方法牛皮了;
想象生活中,有一个跑得快的人和跑步慢的人同时开始跑步,假如两个人匀速一起跑:
如果是围着操场跑,那么总有一个时候这个跑得快的人会追上跑得慢的人(假如这两个人都不要命的可以一直跑:))
如果是一条康庄大道没有拐弯,那么这个跑得快的人一定先到达终点,而且永远不会再看到这个跑得慢的人。
根据此思想,可以得出,我在链表开始的地方设置两个游标,一个游标p走得快,一个游标q走得慢,那么,p要是q的几倍速度才能尽快得出他们是否会相遇的结论呢?
生活中,假如你想快速追上在你后面的那个人(环形跑道中),那肯定是你跑得越快越好对吧,这样就能尽快的追到他或者尽快到终点,也就能尽快得出结论到底是在直线跑还是绕圈跑。但是实际上,跑步这个过程中,是一条连续不断的线,你跑过的路程一定是一条线,你不会错过每一个可能在使你拐弯的点,而在这个问题中,假如你让跑得快的人每次跑两步,那么在未知是否有拐弯的地方和具体在哪里的情况下有一定概率你会错过这个拐弯的地方,因此你可能需要付出跑更多圈来遇到这个拐弯点,(如果你的速度设置得很奇怪,你可能根本遇不到这个拐弯点,但是你又一直在里面跑寻找这个拐弯点,程序必然崩溃)。
所以,最妥当的方法是尽可能的只比跑得慢的快一点点。
相信通过这个比喻,对这个方法是很好理解并且会让人感觉,我去,有意思,希望我的表述能够让你们get到一些收获~