首先吐槽一下这题目
Note that pos is not passed as a parameter.
样例
Input: head = [3,2,0,-4], pos = 1
Output: true
Input: head = [1,2], pos = 0
Output: true
Input: head = [1], pos = -1
Output: false
题目最后一句的 pos 让我百思不得其解,看了样例,我甚至觉得只用判断 pos 是否为 -1不就完事了,但是当我又看到传入参数没有 pos,我又懵了,直到我看了下题解,又尝试敲了如下代码并运行
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode head1 = head;
int n = 0;
while (n < 15) {
int a = head1.val;
System.out.print(a);
head1 = head1.next;
n++;
}
return true;
}
}
看到 stdout 我才明白原来 pos 是给测试机用的,是让数组的最后一个元素指向下标为 pos 的元素,而不是给用户传参用的!
虽然题目本身不难,但是解题的方法似乎蛮有趣的,可以当拓宽思路的题
JAVA
① 存放到集合中
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while (head != null) {
if (set.contains(head))
return true;
set.add(head);
head = head.next;
}
return false;
}
}
② 递归逐个删除
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null)
return false;
if (head.next == head)
return true;
ListNode nextNode = head.next;
head.next = head;
return hasCycle(nextNode);
}
}
我们只需要将每个 head 的 next 指向当前元素(自己),当往下递归时,只要存在环,那么总会遇到指向当前元素(自己)的 head
③ 先反转再比较
public class Solution {
public ListNode reverseList(ListNode head) {
ListNode ans = null;
while (head != null) {
ListNode temp = head.next;
head.next = ans;
ans = head;
head = temp;
}
return ans;
}
public boolean hasCycle(ListNode head) {
ListNode rev = reverseList(head);
if (head != null && head.next != null && rev == head) {
return true;
}
return false;
}
}
如果有环,那么链表反转之后,原来的头结点和反转之后的头结点一定是同一个,可以仔细想想链表反转的过程,head 一直往箭头方向前进,经过了一个环,必跟着箭头回到最初的起点
链表反转的基本用法可以看看这篇博客
④ 快慢指针(单双步)
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == 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;
}
}
慢指针每次前进一步,快指针每次前进两步,主要矛盾就在于快慢指针是否一定会相遇?会不会快慢指针每次都是擦肩而过,而不是正好在某一点重合?
解答:将慢指针看成相对静止的,那么快指针总会在某一时刻追上慢指针
⑤ 快慢指针(任意步)
当快慢指针速度差为 1 的时候,必会在环内相遇,速度差不为 1 的时候,可能会相遇,但不是任意速度组合都会相遇,与环长有关,数学证明涉及线性同余方程的解法
Python
① 存放到列表中
class Solution:
def hasCycle(self, head: ListNode) -> bool:
ans = [] # python列表,永远滴神
while (head):
if head in ans:
return True
else:
ans.append(head)
head = head.next
return False
② 先反转再比较
class Solution:
def hasCycle(self, head: ListNode) -> bool:
if not head or not head.next:
return False
ans, tmp = None, head
while head != None:
head.next, ans, head = ans, head, head.next
return ans == tmp
③ 快慢指针(单双步)
class Solution:
def hasCycle(self, head: ListNode) -> bool:
if not head or not head.next:
return False
slow = head
fast = head.next
while slow != fast:
if not fast or not fast.next:
return False
slow = slow.next
fast = fast.next.next
return True