链表成环或多分枝问题

问题概述

这类问题主要和数论结合到一起。

这类问题主要的解决技巧就是画图,跟着图来写代码,不然代码5分钟,调试2小时。

因为每个节点可以指向下一个节点,那么两个节点就可以指向同一个节点;或者链表的末尾节点指向链表前面的节点。这两种情况分别对应了多分枝和成环。那么针对这两种问题我们展开讨论。

再此之前几个需要掌握的算法

快慢指针

快慢指针就是我们在遍历链表的时候,需要创建一个指针向链表的末尾移动。而我们可以定义一个快指针和一个慢指针,一个走一个节点,一个走x个节点。

那么其中最典型的题目就是返回链表的中间节点,如果是偶数个节点就返回中间靠后的节点。

那么我们让指针可以一个走一个节点一个走两个节点,当快指针走到末尾的时候,我们的慢指针也就到中间了

我们通过画图看到两种fast指针到达最远的停止位置时候,我们的slow都可以到达所需点

看代码:

也是非常的快。时间复杂度是0(N);

我们再看一个不同的快慢指针;

那么这题需要一点逆向思维,肯定fast指针在末尾,slow指针在k处,那么将slow指针退回原点,fast指针就是离原点k个节点的位置。那么我们就知道如何做了。先让fast指针走k个节点,再让两个节点同时运动到末尾。

链表的逆置

链表的逆置很好理解,就是将指的方向反过来。链表逆置有很多种方法,我在这里一一列举出来

第一种就是对原链表进行操作,操作就是要建立三个指针begain,mid,end,不然无法完成:前两个指针负责交换节点指向的方向,后一个是跳向下一个指针。

我们想象一下结束的情况,end指针为NULL此时就结束了,但是此时的begain和mid还没操作

不用说我们直接看代码:

也是非常的快

我们还有一种方法就是,头插一个新链表出来。

这两种算法的综合运用

这个题我想到了两种方法第一种就是用上面的算法,第二种就是用栈来进行。

第一种

我们先找到中间节点,然后我们再将中间节点后面的链表进行逆置,最后我们再从第一个节点和中间节点来同时向后比较。

第二种

我们可以用栈储存前面一半的数据,然后出栈和后面的数据进行比较。

引例

我们j继续通过几个力扣题来认识这类问题。

例一:相交链表

这个就是我们第一个题,属于多分枝.

这个题我有两个思路。

第一个是先遍历B,将所有B的节点存起来,再逆置A,再遍历B与开始的B节点进行比较。第一个不同的节点就是我们要的答案。

这里请大家自己实现。

我们再说另一种方案:

这个方法我们要用到快慢指针。我们先要讲两个链表遍历一遍,统计他们的长度,然后找到并排的位置,从这个位置开始遍历,这样我们遍历下去如果遇到重复的节点就能找到了。

例二:环形链表一

这个就仅仅是判断是否为环链表,我们可以使用可快慢指针来进行操作。一个指针在环里面走一格一个节点,一个指针走两个节点,如果是环那么终究会出现快指针追到慢指针的情况。

我们要先让指针运动再判断,否则第一次就跳出循环返回true了。

如果出现了NULL指针,肯定就不是循环链表,退出循环返回false;

这里我有一个问题:如果我们不要快指针为2倍,而是3被或者N倍速,那么这两个指针是否还能相遇呢?

我们来进行数学讨论:

先从3倍开始:

我们再看每次移动的时候,两者的相对位移会减小2个单位。那么有3t=P+t,就有2t=P,那么我们必须保证P是偶数才能够搞好追上。那么如果我们快指针是超过了怎么办呢(没追上就是超过的前一步,所以只用讨论快指针追上的情况)。我们发现只有一种追上的情况,就是快指针刚好比慢指针多一个单位。那么我们下一次要讨论的就是C-1是否是奇数还是偶数,如果是偶数,那么下一次就可以追上了,如果是奇数,那么还是会出现快指针超过慢指针一个单位的情况。总结的说:我们要保证1:3的速度能够刚好追上,就必须保证P为偶数或者C-1为偶数。

那么3倍速都有这么多不确定,那么后面的N倍速就更不用说了。

所以我们选择两倍速来保证100%的能追上。

例三:环形链表二

这个题目有两种解法。我们先说比较容易想到的解法

解法一

我们先用上面环形链表一的算法来判断一下是否为环形链表,然后还会得到一个相交的节点。那么我么可以从这个节点断开,那么就将这个题目变成“相交链表”的题目了。

解法二

这个方法我们可能不容易想到:

让两个slow指针同时从fast和slow相交的点和起点开始走。两个slow的交点就是我们要找的。

具体证明如下:

这个 L=(X-1)C+N的表达式有什么用呢?

如果我们用slow来走一遍就是:起始点的slow走到相交点的时候,我们k点的slow刚好走了x-1圈加上n的长度。那么就刚好在交点相交。

那么我们试着写一下代码:

能够熟练掌握这几个估计能够解决这一类的问题了。

  • 45
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值