算法详解(力扣141——环形链表系列)

这篇具有很好参考价值的文章主要介绍了算法详解(力扣141——环形链表系列)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

博主ID:代码小豪

环形链表

先来看看环形链表的原题:

算法详解(力扣141——环形链表系列),算法,leetcode,链表
中间的部分叙述有点繁杂,简单来概括就是,假如有一个节点,如果一直调用该节点的next,最后会回到该节点,那么这个链表就是带环的。

环形链表的性质分析

假如有个cur指针从头开始遍历链表,如果这个链表不是环形链表,那么这个cur指针会遍历至NULL指针处
算法详解(力扣141——环形链表系列),算法,leetcode,链表
那么让一个指针从头开始遍历整个链表,如果这个指针到了NULL,就说明这个链表,不是环形链表。

	while (cur)
	{
		cur = cur->next;
	}
	return false;

但是如果这个链表是环形链表该如何证明呢?因为环形链表中是不在空节点的(NULL)。如果cur一直遍历,那么迭代就会进入死循环
算法详解(力扣141——环形链表系列),算法,leetcode,链表

解决思路就是在环形链表当中加入一个标志指针,让这个指针处于环形处。
算法详解(力扣141——环形链表系列),算法,leetcode,链表
这样子让cur指针继续遍历链表,最后一定会遇上flag指针,证明这个链表是环形链表

快慢指针法

那么问题来了,如何让flag指针处于环内呢?因为如果计算机知道flag处于什么位置是环内,我又何必写一大堆代码证明这个链表是环形链表呢?而且如果这个链表不带环,那么flag又应该在什么位置呢?

为了解决这个问题,我们可以设置两个指针指向第一个节点,一个是快指针fast,一个是慢指针slow,让快指针一次递进多个节点,而慢指针依次递进一个节点,让这个操作进行循环。

如此操作,会发生两种情况

情况1,链表为非带环链表,fast指针来到空节点处(NULL),返回false

算法详解(力扣141——环形链表系列),算法,leetcode,链表
情况2,链表为带环链表,fast指针会一直循环遍历环形链表。slow一定会进入环内。
算法详解(力扣141——环形链表系列),算法,leetcode,链表
fast会在链表内循环遍历,所以fast有可能会和slow重合,如果fast和slow重合了,就说明这个链表是环形链表。

指针的追及相遇问题

通过前面前面分析可知,如果该链表是环形链表,那么快指针就有可能在环内与慢指针相遇,那么会不会发生快慢指针不会相遇的情况呢?

首先快指针一定是比慢指针移动更快的,我们假设快指针每次移动两个节点,慢指针每次移动一个节点。

我们假设现在有一个环形链表,这个链表的入口点为点P。

设慢指针来到入口p时,快指针与慢指针的距离为N

算法详解(力扣141——环形链表系列),算法,leetcode,链表
慢指针走一步,快指针会走两步,因此这两个指针的距离会随着执行次数,每次减一(慢指针的走1步,快指针的会走2步,那么快指针相距慢指针就近了一步)。

次数 距离
0 N
1 N-1
2 N-2
依此类推
N-2 2
N-1 1
N 0

可以发现,如果快指针走两步,慢指针走一步,那么这两个指针一定会在环中相遇。

那么如果快指针一次移动三个节点,慢指针一次移动一个节点,我们能得出什么样的结论呢?

还是假设当慢指针到达入口点距离快指针的距离为N
算法详解(力扣141——环形链表系列),算法,leetcode,链表
当慢指针与快指针的距离N为偶数时

次数 距离
0 N
1 N-2
2 N-4
依次类推
N/2-1 2
N/2 0

当N为偶数时,快慢指针会相遇

当快指针与慢指针之间的距离为奇数时

次数 距离
0 N
1 N-2
2 N-4
依次类推
N/2-1 1
N/2 -1

可以发现快指针会越过慢指针,此时快指针会比慢指针多一个节点左右的距离,快指针需要再次遍历整个环形链表,直到与慢指针相遇。
算法详解(力扣141——环形链表系列),算法,leetcode,链表
设环形链表的周长为C,那么此时快指针与慢指针的距离为C-1.

当C为奇数时,C-1为偶数

那么程序的运行次数与快慢指针的距离关系为

次数 距离
0 C-1
1 C-3
2 C-5
依次类推
(C-1)/2-1 2
(C-1)/2 0

由此推出,当N为奇数,C为奇数时,快指针最后会追上慢指针。

当C为偶数时,C-1为奇数

次数 距离
0 C-1
1 C-3
2 C-5
依次类推
(C-1)/2-1 1
(C-1)/2 -1

可以发现快指针和慢指针的距离在这一次追及之后,快慢指针的距离又回到了C-1。所以当N为奇数,C为偶数(C-1为奇数)时,快指针走三个节点,慢指针走1个节点的方式会永远不会相遇。

综上所述,如果我们想用快慢指针相遇的方式证明环形链表,最好的方法是让快指针一次后进两个节点,而慢指针一次后进一个节点。

当快指针后进多个(大于等于2)的节点时,有可能会出现快慢指针永远无法相遇的情况。比如当快指针后进3个节点时,如果此时N为奇数,C为偶数时,快指针永远无法与慢指针相遇,从而导致死循环的出现

解题代码如下:

bool hasCycle(struct ListNode *head) {
    if(head==NULL)
    return false;
    struct ListNode*slow=head;
    struct ListNode*fast=head->next;

    while(fast)
    {
        if(fast->next==NULL)
        return false;

        fast=fast->next->next;
        slow=slow->next;

        if(fast==slow)
        return true;
    }
    return false;
}

环形链表(2)

算法详解(力扣141——环形链表系列),算法,leetcode,链表
这是前面环形链表的变形体,这个OJ的要求是这样的:假设这是一个环形链表,那么就要找到这个链表的入口节点,并将这个节点返回。如果是非环形链表,则返回NULL指针。

首先,我们将这个问题的实现分为两个部分,第一、我们要先确定这是一个环形链表,然后,我们求出这个环形链表的入口点。

确定环形链表的方法已经说明过了,现在要思考的是如何找到这个入口点。

我们首先来思考一下快慢指针的位移关系,已知,快指针的速度是慢指针的两倍,因此当慢指针来到入口点L时,快指针已经移动2L了。

我们假设从链表头到入口点的距离为L,从入口点到达相遇点的距离为N,环形链表的周长为C。
算法详解(力扣141——环形链表系列),算法,leetcode,链表

如果L>C。假如slow移动了L的距离来到入口点,可以知道fast移动距离为2L,在圈内循环了x圈(x至少为1)
当slow来到相遇点时,那么slow移动的距离是L+N,而fast移动的距离为L+N+(x+1)C。

如果L<C。假如slow移动了L的距离来到入口点,可以知道fast移动距离为2L,在圈内循环了0圈
当slow来到相遇点时,那么slow移动的距离是L+N,而fast移动的距离为L+N+C。

根据fast的位移是slow的两倍可以得出:
当L>C时,2(L+N)=L+N+(x+1)C。
当L<C时,2(L+N)=L+N+C。

可以合并成一个公式:
2(L+N)=L+N+yC。(y>=1).

合并同类项得L=yC-N。
我们可以图中明显的看出一个关系
算法详解(力扣141——环形链表系列),算法,leetcode,链表

如果一个指针从相遇点移动YC-N个节点时,会来到入口点。而且一个指针从链表头开始移动L位时,回来到入口点。
并且L=yC-N。

可以得出,如果让一个指针从链表头开始移动,一个指针从相遇点开始移动。这两个指针会在入口点相遇。

代码如下:文章来源地址https://www.toymoban.com/news/detail-826832.html

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*fast=head;
    struct ListNode*slow=head;

    while(fast)
    {
        if(fast->next==NULL)
        return NULL;
        fast=fast->next->next;
        slow=slow->next;

        if(fast==slow)
        {
            struct ListNode*meet=slow;

            while(meet!=head)
            {
                meet=meet->next;
                head=head->next;
            } 
            return meet;
        }
    }
    return NULL;
}

到了这里,关于算法详解(力扣141——环形链表系列)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode 141.环形链表

    题目链接 👉 LeetCode 141.环形链表👈 给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始

    2024年02月12日
    浏览(28)
  • LeetCode[141] [142] 环形链表I II

    141. 环形链表 - 力扣(LeetCode) 142. 环形链表 II - 力扣(LeetCode) 题解: 快慢指针题 从head开始,一个快指针,一次前进两步,一个慢指针,一次走一步 如果没有环,则快指针首先到达链表尾部, 如果有环,快慢指针肯定能相遇即fast=slow 141代码: 对于142需要环的起点,需要

    2024年02月04日
    浏览(31)
  • 单链表OJ题:LeetCode--141.环形链表

    朋友们、伙计们,我们又见面了,本期来给大家解读一下LeetCode中的第141道单链表OJ题,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! 数据结构与算法专栏 :数据结构与算法 个  人  主  页  :stackY、 C 语 言 专 栏 :C语言:从入门到精通 LeetC

    2024年02月08日
    浏览(45)
  • leetcode 141.环形链表 I - 142.环形链表 II 代码及指针相遇证明问题

    给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 如果链表中存在环 ,则返回 true 。 否则,返回 false 。 思路: 快慢指针问题 。我们可以声明一个 fast 指针(一次走两步),声明一个 slow

    2024年02月12日
    浏览(53)
  • [LeetCode]-160. 相交链表-141. 环形链表-142.环形链表II-138.随机链表的复制

    目录 160.相交链表  题目 思路 代码  141.环形链表  题目 思路 代码 142.环形链表II 题目 思路 代码 160. 相交链表 - 力扣(LeetCode) https://leetcode.cn/problems/intersection-of-two-linked-lists/description/ 给你两个单链表的头节点  headA  和  headB  ,请你找出并返回两个单链表相交的起始节点

    2024年02月05日
    浏览(37)
  • 【每日OJ题—— 141. 环形链表(链表)】

    2.1 解法 2.1.1 图文解析 我们可以根据上述思路来解决本题。具体地,我们定义两个指针,一快一慢。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针在位置 head,而快指针在位置 head.next。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该

    2024年02月05日
    浏览(32)
  • 链表专题1—24. 两两交换链表中的节点 234.回文链表 143.重排链表 141.环形链表 142.环形链表II 160.链表相交 C++实现

    迭代法,时间复杂度: O ( n ) O(n) O ( n ) , 空间复杂度: O ( 1 ) O(1) O ( 1 ) 时间复杂度、空间复杂度: O ( n ) O(n) O ( n ) 止位置时,慢指针就在链表中间位置。 同时用pre记录慢指针指向节点的前一个节点,用来分割链表,将链表分为前后均等两部分,如果链表长度是奇数,那么

    2024年02月12日
    浏览(31)
  • 【LeetCode 算法】Linked List Cycle II 环形链表 II

    给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从

    2024年02月14日
    浏览(32)
  • 力扣每日一道系列 --- LeetCode 206. 反转链表

    📷 江池俊: 个人主页 🔥个人专栏: ✅数据结构探索 ✅LeetCode每日一道 🌅 有航道的人,再渺小也不会迷途。 LeetCode 206. 反转链表 初始化两个指针, cur 和 newhead 。 cur 指向给定的链表头节点, newhead 初始为 NULL 。 在 cur 不为空的情况下,执行循环。 首先,记录下 cur 的下

    2024年02月04日
    浏览(31)
  • 力扣每日一道系列 --- LeetCode 160. 相交链表

    📷 江池俊: 个人主页 🔥个人专栏: ✅数据结构探索 ✅LeetCode每日一道 🌅 有航道的人,再渺小也不会迷途。 LeetCode 160. 相交链表 思路: 首先计算两个链表的长度,然后判断两个链表的尾节点是否相同。如果不同,那么这两个链表就没有交集,返回空;如果相同,那么就

    2024年02月05日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包