记录力扣刷题第九题
本文包含C++解法和Java、Python解法
题目描述如下
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
提示:
链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引
来源:LeetCode
思路:
看到这题没啥思路,本来想暴力试一下,结果发现数据量给的挺大的,暴力肯定过不了。于是我冥思苦想,想到了可以用快慢指针遍历链表判断是否成环的方法,可是怎么找到入环的第一个结点呢?想了半天还是想不出来办法,于是我就看了看题解。
果然是用快慢指针,快指针一次走两步,慢指针一次走一步,两者速度之差为1,这样就能保证有环时在慢指针没走完一圈的时候就被快指针追上,也就能判断成不成环。
而如何找到入环的第一个结点就需要一些数学知识了。首先看下图:
借用力扣官方题解的图片,紫色点为相遇点,直线圆圈交界点为入口。
计算出a,b,c之间的关系需要如下等式
- 不妨设相遇时快指针绕圈走了n圈
- 快指针走过的路程为a+b+n(a+b)
- 慢指针走过的路程为a+b
- 快指针的速度是慢指针的两倍,所以相遇时路程也是两倍,则 2(a+b)=a+n(b+c)+b
解得a=c+(n-1)(b+c),即从头结点到入口的距离等于n-1个环的长度加上从相遇点到入口的距离,并且n>1时a一定大于b+c,n<=1时a==c。因此可以在头结点与相遇点分别放置一个指针,进行遍历,这两个指针的相遇点即为入口。
代码如下
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
//链表结点定义
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
//对快慢指针初始化
ListNode* fast = head;
ListNode* slow = head;
//fast直接跑下下个了,因此要对下个也进行判断
while(fast != nullptr && fast->next != nullptr) {
//一步两步
fast = fast->next->next;
slow = slow->next;
if(fast == slow) {
//如果成环
ListNode* index1 = head;
ListNode* index2 = slow;
//遍历相遇找到入口
while(index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
//不成环返回空
return nullptr;
}
};
接下来放上Java与Python的代码
Java
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
//链表结点定义
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if(fast == slow) {
ListNode idx1 = head;
ListNode idx2 = slow;
while(idx1 != idx2) {
idx1 = idx1.next;
idx2 = idx2.next;
}
return idx1;
}
}
return null;
}
}
Python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
# 链表结点定义
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
fast = head
slow = head
while True :
if fast == None : return None
if fast.next == None : return None
fast = fast.next.next
slow = slow.next
if fast == slow :
idx1 = head
idx2 = slow
while idx1 != idx2 :
idx1 = idx1.next
idx2 = idx2.next
return idx1