题目描述:来自LeetCode
方法一:hash表
我们很容易想到这种遍历然后做标记的方法来判断是否遍历过,如果遍历过又回到了这个节点,那就一定存在环,可以用hash表存储,在java里HashSet存储的元素不可重复,当某个元素在hash表里已经存在就会返回false并且不存储,(关于HashSet可以看看我的这个博客HashSet存储元素唯一性源码分析),那我们一边遍历一边将结点放入集合,如果失败就说明该元素已经存在,则是环形链表。在C++里有一个unordered_set,该集合有一个判断元素在集合里出现的次数的方法,在遍历的时候,判断每个结点在集合里出现的次数,如果次数不等于0就说明该结点已存在,则证明是环形链表。
代码实现C++:
class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode *> set;
while(head){
if(set.count(head)){
return true;
}
set.insert(head);
head=head->next;
}
return false;
}
};
代码实现java:
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> s=new HashSet();
while(head!=null){
if(!s.add(head)){
return true;
}
head=head.next;
}
return false;
}
}
方法二:快慢指针!!
空间复杂度直接O(1)了,关于快慢指针可以做一下LeetCode中的求链表的倒数第k个元素,同样也是用快慢指针,解决了另一个问题,所以这个算法还是很重要的哦!
快指针每次移动两步,慢指针每次移动一步,如果存在环,则快指针一定会在某一圈追上慢指针
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *fast=head,*slow=head;
if(head==NULL||slow->next==NULL) return false;
do{
if(fast->next==NULL||fast->next->next==NULL) return false;
fast=fast->next->next;
slow=slow->next;
}while(slow!=fast);
return true;
}
};