142. 环形链表 II

2019-02-20  本文已影响0人  MarkOut

题目链接:

142. 环形链表 II

题目描述:

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos-1,则在该链表中没有环。

说明:不允许修改给定的链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。

算法:

此题其实分为两个部分,检测环形链表和找到循环的起始位置。

检测环形链表其实很简单,141. 环形链表就是一道这样的题目,题目也有官方题解,官方题解十分详细。解法有两个:

对于这道题,如果同样用哈希表,那么就与检测环形链表的代码一样了,也就没有挑战性了。这道题最难的部分是如何使空间复杂度为O(1)

我们同样用快慢指针检测环形链表。假设进入循环第一个结点前的长度为a,整个循环的长度为b,快指针与慢指针相遇的结点距离循环的第一个结点的距离为c。那么根据之前的分析可知,慢指针走过的距离为a + c,快指针走过的距离是a + b + c。并且2(a + c)=a + b + c。由此可知,b = a + c。也就是说,整个循环的长度刚刚好是慢指针走过的路程。

现在我们要求的是a,我们就可以利用这个等式。因为慢指针已经走过a + c的距离了,如果它再走a个结点,则a + c + a=a + b,这刚刚好代表了循环的第一个结点的位置。而如果我们再用一个新的指针,让它从开始走a步,它同样在循环的第一个结点,与原结点相遇。这样,我们就找到了题目要求的循环的第一个结点。

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *p = head, *f = head;
        while (f != NULL && f->next != NULL) {
            p = p->next;
            f = f->next->next;
            
            if (p == f) {
                f = head;
                while (p != f) {
                    p = p->next;
                    f = f->next;
                }
                return f;
            }
        }
        return NULL;
    }
};
上一篇下一篇

猜你喜欢

热点阅读