力扣刷题记录九:142、环形链表Ⅱ

本文通过实例解析了如何使用快慢指针技巧解决LeetCode上的链表环路检测问题,介绍了如何找到链表中第一个入环节点。通过数学分析,结合C++, Java, Python代码实现,为理解链表环路检测提供了深入的教程。
摘要由CSDN通过智能技术生成

记录力扣刷题第九题

本文包含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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值