141.环形链表
目录
- 141.环形链表
- 一、哈希表
- 二、双指针
一、哈希表
最容易想到的方法就是遍历所有节点,每次遍历到一个节点的时候,判断该节点此前是否被访问过
我们可以使用哈希表来存储所有已经访问过的节点
每次到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入到哈希表中,重复这一操作,直到遍历完整个链表为止
值得一提的是,这里我们使用HashSet,Set集合的特点是什么?即该集合中不会出现重复的元素,如此一来,就很好判断了
public boolean hasCycle(ListNode head) {
Set<ListNode> set = new HashSet<ListNode>();
while(head!=null){
//如果向哈希Set中加入节点失败(即该Set中已经有了重复的元素)
if(!set.add(head)){
return true;
}
head = head.next;
}
return false;
}
二、双指针
本题的快慢指针法,需要我们先了解一下Floyd判圈算法
(龟兔赛跑算法)
假设乌龟和兔子从链表上同一节点开始移动,兔子跑得快,乌龟跑得慢,如果链表中没有环
,那么兔子将一直处在乌龟的前方
如果链表中有环
,那么兔子会先于乌龟进入环,并一直在环中移动;等到乌龟进入环后,由于兔子的速度快于乌龟,所以兔子一定会在某个时刻追上乌龟
可以根据这个思路来解决这个问题,我们定义两个指针,一快一慢
。慢指针每次只移动一步,而快指针每次移动两步
初始时,慢指针在head位置,快指针在head.next位置
这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表
否则快指针将到达链表尾部,该链表不为环形链表
public boolean hasCycle(ListNode head) {
if(head==null||head.next==null){
return false;
}
ListNode slow = head;
ListNode fast = head.next;
while(slow!=fast){
if(fast==null||fast.next==null){
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}