​LeetCode刷题实战142: 环形链表 II

共 2339字,需浏览 5分钟

 ·

2021-01-04 20:30

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 环形链表 II,我们先来看题面:
https://leetcode-cn.com/problems/linked-list-cycle-ii/

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.


There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail's next pointer is connected to. Note that pos is not passed as a parameter.


Notice that you should not modify the linked list.

题意


给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
进阶:
你是否可以使用 O(1) 空间解决此题?

样例


解题

思路:用快慢双指针遍历链表

快指针一次移动两步,慢指针依次移动一步。将快慢双指针想象成两个运动员在赛跑,如果链表有环,那么终有一个时刻快慢双指针会重合。一旦某个节点的next节点出现null,说明不是环形链表,直接返回null即可。
如果是环形链表,我们令其中一个指针指向虚拟头节点,而另一个指针则仍然在相遇的那个节点,一起移动这两个指针,直到这两个指针相遇,这个新的相遇点就是链表开始入环的第一个节点。
为什么上述算法得到的点就是链表开始入环的第一个节点呢?
如上图所示,虚拟头节点到第一个入环的节点的距离是x1,第一个入环的节点顺时针出发到相遇点的距离是x2,相遇点顺时针出发到第一个入环的节点的距离是x3。
从dummyHead节点出发到快慢指针相遇的过程中:
第一个慢指针走过的路程长度是x1 + x2 + k1 * (x2 + x3)
第二个快指针走过的路程长度是x1 + x2 + k2 * (x2 + x3)
由快慢指针的速度关系得:(x1 + x2) * 2 + 2 * k1 * (x2 + x3) = x1 + x2 + k2 * (x2 + x3),因此x1 + x2 = (k2 - 2 * k1) * (x2 + x3),进而有x1 - x3 = (k2 - 2 * k1 - 1) * (x2 + x3)。这说明x1和x3的距离差值刚好是环长(x2 + x3)的整数倍。因此,我们只需令其中一个指针指向虚拟头节点,而另一个指针则仍然在相遇的那个节点,一起移动这两个指针,直到这两个指针相遇,这个新的相遇点就是链表开始入环的第一个节点。
时间复杂度是O(n),其中n为链表中的节点个数。空间复杂度是O(1)。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        ListNode cur1 = dummyHead;
        ListNode cur2 = dummyHead;
        while(true){
            if(null == cur2.next || null == cur2.next.next){
                return null;
            }
            cur1 = cur1.next;
            cur2 = cur2.next.next;
            if(cur1 == cur2){
                break;
            }
        }
        cur1 = dummyHead;
        while(cur1 != cur2){
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }
}


好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力。

上期推文:

LeetCode1-140题汇总,希望对你有点帮助!
LeetCode刷题实战141: 环形链表


浏览 30
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报