判断链表是否有环

给定一个单链表,只给出头指针h:

  • 1、如何判断是否存在环?

  • 2、如何知道环的长度?

  • 3、如何找出环的连接点在哪里?

  • 4、带环链表的长度是多少?

解法:

  • 1、对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。

  • 2、对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。

  • 3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。(附加:如果每个节点的元素值不重复,所有节点的元素值排序,第一个重复出现的节点就是。)

  • 4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度

1.判断单链表是否有环

使用两个slow, fast指针从头开始扫描链表。指针slow 每次走1步,指针fast每次走2步。如果存在环,则指针slow、fast会相遇;如果不存在环,指针fast遇到NULL退出。

就是所谓的追击相遇问题:
  在这里插入图片描述

public class LinkListUtli {
class LNode{
    //为了简化访问单链表,结点中的数据项的访问权限都设为public
    public int data;
    public LNode next;
}
    public static boolean hasCircle(LNode L)
    {
        LNode slow=L;//slow表示从头结点开始每次往后走一步的指针
        LNode fast=L;//fast表示从头结点开始每次往后走两步的指针
        while(fast!=null && fast.next!=null) 
        {
            slow=slow.next;
            fast=fast.next.next;
            if(slow==fast) return true;//p与q相等,单链表有环
        }
        return false;
    }
}

证明:
首先,如果存在环,那么快指针和慢指针一定会同时进入到环中。假设当slow指针刚进入环时,fast指针所在的结点编号是a(现在只考虑环中的结点),slow指针所在结点编号是k+a,那么就环展开就像如下图所示:
在这里插入图片描述
由于slow和fast指针都是在环中的,所以可以将环展开的直线无限延伸。如果没有限制,slow和fast指针可以在环中无限的走下去。

​ 假如说是fast和slow指针可以相遇,且相遇的位置为k+m+a(其中m表示slow指针进入环后走了m步就和fast指针相遇了),那么m一定是有解的。
我们简化一下,假设a的位置就是0:
在这里插入图片描述
由于slow指针从k结点走了m步就和fast指针相遇了,则一定有下面的等式成立:
k+m=2m
slow指针走了m步,会到达k+m结点处,相应的fast走了m步会到达2m结点,由于是两个指针走了m步相遇,所以一定有上面的等式成立。由等式可知,m一定是有解的,且m=k
0到k的距离和k到k+m的距离是相同的,而0到k+m是fast指针走的距离,正好slow的2倍。
也就是,如果没有环,一定不会相遇(fast一定会在前面,slow永远追不上);有环,一定会在k+m处相遇(将环无限延长n倍)。

2.求有环单链表的环长

在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步。在下次相遇的时候fast比slow正好又多走了一圈,也就是多走的距离等于环长。

设从第一次相遇到第二次相遇,设slow走了len步,则fast走了2*len步,相遇时多走了一圈:

环长=2*len-len。

3.求有环单链表的环连接点位置

第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,因此,分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。
在这里插入图片描述
在环上相遇后,记录第一次相遇点为Pos,连接点为Join,假设头结点到连接点的长度为LenA,连接点到第一次相遇点的长度为x,环长为R。

第一次相遇时,slow走的长度 S = LenA + x;

第一次相遇时,fast走的长度 2S = LenA + n*R + x;

所以可以知道,LenA + x = nR;  LenA = nR -x; (理解:LenA = n*(R-1) 【保证回到Pos】 + n-x【保证剩下的距离正好到达Join】)

4.求有环单链表的链表长

上述2中求出了环的长度;3中求出了连接点的位置,就可以求出头结点到连接点的长度。两者相加就是链表的长度。

对快慢指针的理解:如果没有环,快指针一定先走完,两个指针不会相遇;如果有环,那么最多只有一个环,并且两个指针迟早都会进入环,假定环的长度为L,当慢指针进入环之后,快指针每次能向前追一步距离,最多只要L-1步就能追上慢指针所以可以用两个指针是否相遇来判断是否有环。

参考:https://www.cnblogs.com/kira2will/p/4109985.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值