一、今日刷题
1. 第五部分:链表 – 142. 环形链表Ⅱ
跳转LeetCode
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
答案代码:
方法①:哈希表,遍历链表中的每个节点,并将它记录下来;一旦遇到了此前遍历过的节点,就可以判定链表中存在环。借助哈希表可以很方便地实现。
package LinkedList;
import java.util.HashSet;
import java.util.Set;
/**
* @author: LYZ
* @date: 2022/2/9 19:40
* @description: 142.环形链表Ⅱ:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
*/
public class DetectCycle {
public static void main(String[] args) {
DetectCycle detectCycle = new DetectCycle();
ListNode head = new ListNode(3);
head.next = new ListNode(0);
head.next.next = new ListNode(5);
ListNode ans = detectCycle.detectCycle(head);
}
public ListNode detectCycle(ListNode head) {
ListNode pos = head;
Set<ListNode> set = new HashSet<>();
while (pos != null) {
if (set.contains(pos)) {
return pos;
} else {
set.add(pos);
}
pos = pos.next;
}
return null;
}
static class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
}
方法②:快慢指针
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
}
ListNode slow = head, fast = head;
while (fast != null) {
slow = slow.next;
if (fast.next != null) {
fast = fast.next.next;
} else {
return null;
}
if (fast == slow) {
ListNode ptr = head;
while (ptr != slow) {
ptr = ptr.next;
slow = slow.next;
}
return ptr;
}
}
return null;
}
}
为何慢指针第一圈走不完一定会和快指针相遇?
首先,第一步,快指针先进入环
第二步:当慢指针刚到达环的入口时,快指针此时在环中的某个位置(也可能此时相遇)
第三步:设此时快指针和慢指针距离为x,若在第二步相遇,则x = 0;
第四步:设环的周长为n,那么看成快指针追赶慢指针,需要追赶n-x;
第五步:快指针每次都追赶慢指针1个单位,设慢指针速度1/s,快指针2/s,那么追赶需要(n-x)s
第六步:在n-x秒内,慢指针走了n-x单位,因为x>=0,则慢指针走的路程小于等于n,即走不完一圈就和快指针相遇
为何 ptr 与 slow 相遇的点就是环的入口?
a=c+(n−1)(b+c)
这个公式说明a一定是n - 1圈加c的长度,这个时候,让ptr和慢指针同时+1着走, 那么慢指针走c之后,ptr到环入口的距离只剩整n - 1圈的距离了,而且此时慢指针也刚好走到入口处了, (因为我们无法确定c是多少,这个时候还得不出结论,那么:) 他俩一起走完n - 1圈的距离之后就会相遇,而且此时正好是入口
小问题
今天还看到了一个有意思的小问题,有一个天平,8个外观相同的小球,其中7个质量相同,1个较轻。最多称两次,找出较轻的那个小球。
答:
第一次称的时候,天平两边各放3个球,剩余2个球。
如果天平平衡,说明较轻的球在剩余的两个球中,第二次称的时候只需称剩余的这2个球即可。
如果天平不平衡,从第一次称时相对较轻的那3个球中选2个做第二次称重。第二次称重时,如果天平平衡,则剩下的那个球就是较轻的;如果天平不平衡,较轻的球也就找到了。