【数据结构与算法】-- 6.2 链表的5个经典操作--单链表检测存在环和求环长

1.如何判断单链表里面是否有环?

设定两个指针,一个慢指针,一个快指针,慢指针每次往前移动一步,快指针同时移动两步。如果链表中存在环,则快慢指针一定会相遇,否则快指针首先遇到null(尾指针);

(1)为什么链表中存在环快慢指针就一定会相遇呢?

举个简单的例子,小红和小明在操场上跑步,小明的速度是小红的两倍,假定他们同时从起点出发,那么小红跑完一圈的到达起点的时候小明一定会跑完两圈同时也到达起点,他们就一定会相遇。
在这里插入图片描述

(2)如果起点不同快慢指针会相遇吗?

如上图示,快慢指针一开始都不在环里,而且他们到达环的起点也不同,那他们还会在环内相遇吗? 答案是肯定的,我们可以稍微计算一下。
思路是:我们先从简单的同起点开始计算然后推广到非同起点的情况。
同起点
第i次迭代时,p指向元素i mod n,q指向2i mod n。因此当i==2i(mod n)时,p与q相遇。
而i=2i(mod n)
=> (2i - i) mod n = 0
=> i mod n = 0
=> 当i=n时,p与q相遇。
非同起点
两个起点不同,速度不同的指针p,q满足什么关系时可以相遇?
Sp(i) = p
Sq(i) = k + qi
则 Sp(i) = Sq(i) => (pi) mod n = ( k+ qi ) mod n
=>[ (q -p)i + k ] mod n =0
=> (q-p)i + k = Nn [N 为自然数]
=> i = (Nn -k) /(p-q)
i 取随机自然数,所以存在自然数N,使得p,q满足上面的等式关系时候相遇。

2. 检测链表中环的长度

如果理解了上面通过双指针相遇检测是否存在环的问题之后这个问题就比较简单了,我们可以记录下第一次两个指针相遇的位置,然后记录下第二次相遇的位置,然后两者之差就是环长了。 不过这里有个前提是我们定义了快指针是慢指针速度的两倍,这样第二次相遇的时候快指针正好又比快指针多走了一圈,也就是多走的距离就等于环长;
公式:
第一次相遇时候,慢指针走了len步,则快指针走了2 * len步。
第二次相遇时候,慢指针走了len+ringLength,则快指针走了2 * len+2ringLeng;
两者之差正好为环长。

3.具体实现

   /**
     * 检测环
     * @param list 单链表
     * @return 是否存在环
     * @author 天赋吉运-杨晓慧
     */
    public static boolean checkCircle(Node list) {
        if (list == null) return false;

        Node fast = list.next;
        Node slow = list;

        while (fast != null && fast.next != null) {
            // slow每走一步,fast同时会走两步
            fast = fast.next.next;
            slow = slow.next;
            // 如果存在环,则指针slow、fast会相遇
            if (slow == fast) return true;
        }
        return false;
    }

    /**
     * 求有环单链表的环长
     * @param ringMeetNode 首次相遇的节点
     * @return 环长
     * @author 天赋吉运-杨晓慧
     */
    public static int getRingLength(Node ringMeetNode){
      // 定义首次相遇地点为0
        int ringLength=0;
        Node fast = ringMeetNode;
        Node slow = ringMeetNode;

        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            ringLength++;
            // 第二次相遇时跳出循环
            if (slow == fast) break;
        }
        return ringLength;
    }

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页