给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle
方法一:
我们可以通过Java中的hashMap来实现当前这个节点是否已经出现过了。如果在遍历这个节点的时候,在hashMap中已经出现过了,那么就说明这个链表存在着环,返回true,否则如果没有出现过,那么就将这个节点压入到hashMap对象中。
对应的代码(Java):
public class Solution {
/*
方法一:利用哈希表,如果这个节点已经在哈希表中已经存在了,那么
就会返回值,表示已经存在了,否则返回null时,表示没有存在,那么
就往哈希表中添加节点,如果遍历到最后,获得这个键对应的值不为null,
表示这个链表中的确存在环
*/
public boolean hasCycle(ListNode head) {
ListNode cur = head;
HashMap<ListNode,Integer> map = new HashMap<ListNode,Integer>();
Integer count;
while(cur != null){
/*
获取当前键对应的值,如果这个值是null,说明这个节点在hashMap对象中并
没有存在,那么就将其压入到hashMap中,否则,值不是null,说明这个节
点之前已经被压入进去过了,此时在遇到这个节点,就说明链表存在着环
*/
count = map.get(cur);
if(count == null){
map.put(cur,1);
}else{
return true;
}
cur = cur.next;
}
/*
必然会有结束程序的时候,要么链表有序,要么无环,如果没有环,那么必
然会有cur为null的时候,所以我们需要在while循环下面添加return
false语句,一旦退出while循环,必然说明没有环
*/
return false;
}
}
方法二:
利用快慢指针的方法。其中pre表示的是慢指针,cur表示的是快指针。其中,如果在某一次循环中,快指针cur等于pre的时候,那么就说明这个链表存在着环,从而使得cur等于pre,否则,如果cur为空的时候,那么这时候就说明链表不存在这个环。
public class Solution {
/*
利用双指针:
pre表示慢指针,cur表示快指针,如果存在环,那么就会存在着
cur等于pre的情况(即两者相遇),但是为了保证能够有机会相遇,那么
cur每一次不可以只移动一个节点,即不可以是cur = cur.next,否则,即使
有环,也不会有相遇的时候。
所以我们将cur和pre一开始都是在head这个节点的位置,然后如果cur这个节点
以及它的下一个节点不为空,我们就继续循环,并且每一次循环中,cur移动两
个节点,即cur = cur.next.next,pre移动一个节点,即pre = pre.next。
值得注意的是,不可以移动三个节点,否则就有可能会造成时间的超时,具体的
原因可以看一下[3,2]这个链表,如果一次移动三个节点的话,就有可能陷入了
死循环,从而超时。
*/
public boolean hasCycle(ListNode head) {
ListNode cur = head,pre = head;
while(cur != null && cur.next != null){
/*
当前的节点不为空,并且当前节点的下一个节点不为空的时候,就继续进行
循环,之所以循环条件中还需要添加cur.next != null,是因为cur =
cur.next.next这个语句的影响,如果cur.next为空了,那么cur =
cur.next.next就会发生报错,提示NullPointerException的错误.
*/
cur = cur.next.next;
if(cur == pre)
return true;//如果相等,说明存在环,返回true
pre = pre.next;
}
return false;
}
}