题目描述
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
}
}
题目分析
- 代码中给定了一个头结点,那么就是通过这个头结点遍历
- 一种解法是,将遍历过的结点做一个标记,放入读过的结点集合中,直到全部读完,如果都还没有读到已经读过的结点,那就说明没有环
- 第二种解法就是双指针法,一个指针移动快,一个指针移动慢,如果有环形,那么两个指针一定能够遇到
解法分析
- 如果使用第一种解法,对于含有 n 个元素的链表,我们访问每个元素最多一次;空间取决于添加到哈希表中的元素数目,最多为n,所以时间复杂度和空间复杂度都是 O(N)
- 如果使用第二种解法:【分析来自官方题解】
代码
- 解法一,来自官方
public boolean hasCycle(ListNode head) {
// 已经读取过的结点集合
Set<ListNode> nodesSeen = new HashSet<>();
// 遍历所有结点
while (head != null) {
// 如果当前读取的结点已经读取过了,那就说明有环
if (nodesSeen.contains(head)) {
return true;
} else {
// 如果没有读取过,就放入读取过的结点集合
nodesSeen.add(head);
}
// 移动指针
head = head.next;
}
// 没有环返回false
return false;
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/linked-list-cycle/solution/huan-xing-lian-biao-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 解法二,双指针法
public class Solution {
public boolean hasCycle(ListNode head) {
// 当空结点和只有一个结点的时候,直接返回false
if (head == null || head.next == null) return false;
// 双指针,一快一慢
ListNode a = head, b = head.next;
// 当链表没有遍历到结尾时
while(a != null && b != null && b.next != null){
// 如果两个指针相遇
if(a == b) {
return true;
}
// 没有相遇就移动指针
// 慢指针一次移动一个位置
a = a.next;
// 快指针一次移动两个位置
b = b.next.next;
}
// 如果遍历完了还没有相遇就说明没有环
return false;
}
}