题目要求
原题目链接:141. 环形链表
题目要求如下:
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
示例如下:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
ListNode节点结构如下:
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
解法1:Set集合储存遍历过的节点
思路
根本思路是在遍历过程中判断当前被遍历的节点此前是否被访问过。
链表如果成环的情况下,那么意味着链表中的环部分在遍历过程中一定会被多次遍历,那么只需要将遍历过的节点保存在一个容器中,每次遍历在容器中进行搜索判断,如果容器中已经存在了当前遍历的节点,则说明当前链表有环,且第一个重复出现的节点就是环的入口节点。
复杂度
- 时间复杂度:O(n),最坏情况是一次对链表的遍历
- 空间复杂度:O(n),最坏的情况是额外存储整个链表
n为链表中的节点数
AC代码
public class Solution {
public boolean hasCycle(ListNode head) {
HashSet<ListNode> hashSet = new HashSet<>();
while(head != null){
if(hashSet.contains(head)){
return true;
}
hashSet.add(head);
head = head.next;
}
return false;
}
}
解法2:快慢指针
思路
设置两个指针对链表进行遍历,指针遍历速度一快一慢。
- 链表中无环的情况:快指针最终会先遍历完链表,快指针遍历结束等于null时表示链表无环。
- 链表中有环的情况:在环路中,两个指针一快一慢的遍历,最总速度快的指针一定会追上速度慢的指针,也就是说如果在遍历过程中发现快指针和慢指针的指向相同,意味着链表有环。
复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(1),只额外需要两个指针
n为链表中的节点数
AC代码
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast != null){
fast = fast.next;
if(fast == null){
return false;
}
fast = fast.next;
slow = slow.next;
if(fast == slow){
return true;
}
}
return false;
}
}