【题解】剑指 Offer II 022. 链表中环的入口节点(map)(双指针)(快慢指针)

题目链接

 力扣

题目描述

给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。

示例 1:

 

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:

 

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:

 

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
 

提示:

链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引

解题思路

 map法比较简单,但是会浪费空间

此处只需要记住map也可以存储出现过得节点就可以了

此处重点说一下双指针的解法

利用快慢指针,fast指针一次走两步,slow指针一次走一步

        如果没有环的话,总会有一步fast==NULL或者fast->next==NULL,这时直接返回NULL即可

        如果有环的话,slow和fast总会相遇,因为fast始终比slow快一步,类似于操场跑圈,如果一个人一直比你跑得快,你俩在操场上一直跑,总会有一个时间两个人会相遇

        假设链表头部到环的入口的长度为a,环有b个节点

根据题目可知,fast走的步数为slow的两倍,有 fast=2*slow

又因为fast比slow走的快,两者同一个起点,fast要么比slow先进入环(a>0的时候),或者fast和slow同时进入环(a==0的时候),当两者再一次相遇后,说明fast最少套了slow一圈,所以假设fast套了slow n圈,那么有fast=n*b+slow

由两式子可以推导出slow=n*b,fast=2*n*b,说明当fast走了n个周长时,slow走了2n个周长

又有从链表的起点走k步能到环的起点,那么有k=a+nb,走a步说明第一次到入口节点,其后每加一次b,就说明就过一次入口节点(跑完一圈回到起点)

又因为slow=nb,所以只要在想办法让slow走a步就可以让slow到环的入口节点,可以让fast回到起点,然后让fast和slow以相同的速度同时走,当fast和slow再次相遇,说明fast走了a步到达了环的入口,slow也走了a步到达了环的入口,所以两者相等

题解

双指针 

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast=head;
        ListNode* slow=head;
        while(fast&&fast->next&&fast!=slow){
            fast=fast->next->next;
            slow=slow->next;
        }
        if(fast==NULL&&fast->next==NULL)  return NULL;
        fast=head;
        while(fast!=slow){
            fast=fast->next;
            slow=slow->next;
        }
        return fast;
    }
};

 map

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        map<ListNode*,int> ma;
        while(head){
            if(ma[head]!=0) return head;
            ma[head]++;
            head=head->next;
        }
        return NULL;
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值