LeetCode (27) Linked List Cycle (判断cycle存在、寻找cycle入口节点)

判断cycle存在

Given a linked list, determine if it has a cycle in it.

Follow up: Can you solve it without using extra space?

本题要求判断给定链表中是否存在循环。并且题目要求不要使用extra space,因此,我们就不能保存每一个结点的value,在遍历的时候判断是否是循环。这道题可以通过使用速度不同的pointer进行遍历,若两个pointer相遇则说明存在cycle,若遇到NULL指针,则不存在cycle。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if (!head)
            return false;

        ListNode* l1 = head;
        ListNode* l2 = head;

        while(true)
        {
            if (!l1 || !l2)
                return false;
            l1 = l1->next;
            if (!l1)
                return false;
            l1 = l1->next;
            l2= l2->next;

            if (l1 == l2)
                return true;
        }
    }
};

寻找cycle入口结点

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

Follow up: Can you solve it without using extra space?

本题在上一题的基础上,进一步要求我们给出循环的入口结点,如下图中入口结点为3.

由第一题我们可以判断链表是否存在循环,若存在循环,两个pointer会在结点 l 处相遇,此时给出一个结点 h=head,h 和 l 同时遍历,若 h=l (h 和 l 相遇),则相遇处的结点为头结点。

/**
 * 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) {
        if (!head)
            return false;

        ListNode* l1 = head;
        ListNode* l2 = head;

        while(true)
        {
            if (!l1 || !l2)
                return NULL;
            l1 = l1->next;
            if (!l1)
                return NULL;
            l1 = l1->next;
            l2= l2->next;

            if (l1 == l2)
                break;
        }

        l1 = head;
        while (l1 != l2)
        {
            l1 = l1->next;
            l2 = l2->next;
        }

        return l1;
    }
};

解法证明

相信运行过上面代码的同学可以发现以上解法确实是正确的,但是这个解法看起来并不是很直观,为了打消同学们的疑虑,下面我将证明上面解法的正确性。

如上图所示的链表,循环外长度设为 a, 循环长度为 b, 链表长度为 a+b=length。

假设有两个指针分别为 l1 和 l2, l1 以速度为 1 ,l2 以速度为 2 ,从头结点出发遍历链表。所以初始条件:

  • l1=head,v1=1
  • l2=head,v2=2

假设两个指针相遇的位置为 t,l1此时前进的步长为 x。根据两个指针第一次相遇的位置,(在循环中的距离只差了一圈就相遇了)也就是我们有以下关系:

x=a+(n?1)?b+t??????????????(1)

2?x=a+n?b+t?????????????????(2)

这里,由(2)式减(1)式,得到:

x=b

也就是说如果存在循环的话,两个指针肯定会相遇,且相遇时指针前进的步数等于循环列表的长度。使用上面的图中的例子,我们可以看出, a=2, b=4,所以相遇时两个指针位于元素 5 所在的位置。

到此我们得到了判断循环存在的证明结果,下面证明获取循环入口结点的解法。

在第一题中两个指针相遇时,前进的步长为循环的长度 b,对前进速度为 1 的指针来说,停留的位置就是 b+1 处,而链表长度为 a+b,所以指针只用再前进 a?1 步就可以达到链表的最后一个结点(也就是上图中的结点6),此时指针再前进一步就达到的循环的入口结点。

但是根据上面的思路我们存在一个问题,我们并不知道 a 和 b 的大小是多少,这里就要引入另一个从头结点出发的指针了。当该指针与上一题中相遇后的指针,同时以步长为 1 遍历时,经过 a 步均达到了循环的入口结点。因此,根据这个思路我们写了上面第二题的代码。

时间: 2024-10-09 19:50:17

LeetCode (27) Linked List Cycle (判断cycle存在、寻找cycle入口节点)的相关文章

[leetcode]141. Linked List Cycle判断链表是否有环

Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using extra space? 题意: 给定一个链表,判断是否有环 思路: 快慢指针 若有环,则快慢指针一定会在某个节点相遇(此处省略证明) 代码: 1 public class Solution { 2 public boolean hasCycle(ListNode head) { 3 ListNode f

Linked List Cycle 判断一个链表是否存在回路(循环)

Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using extra space? 注意,链表循环并不是尾指针和头指针相同,可能是在中间某一段形成一个环路,所以不能只判断元素和第一个元素是否存在重合 先设置两个指针p_fast和p_slow.从头开始遍历链表,p_fast每次走两个节点,而p_slow每次走一个节点,若存在循环,这两个指针必定重合: 1 /**

[LeetCode 题解]: Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Follow up:Can you solve it without using extra space? 题意: 给定一个链表,找到环起始的位置.如果环不存在,返回NULL. 分析: (1)首先要判断该链表是否有环.如果没有环,那么返回NULL. (2)其次,当已知环存在后,寻找环起始的位置. 思路: (

[LeetCode][JavaScript]Linked List Cycle

Linked List Cycle Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using extra space? https://leetcode.com/problems/linked-list-cycle/ 判断链表是否有环. 先是用了额外空间的做法. 移出每个访问过的节点,指向头节点,如果遇到了指向头节点的点,说明有环. 1 /** 2 * @par

【Leetcode】Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Follow up: Can you solve it without using extra space? 思路:由[Leetcode]Linked List Cycle可知,利用一快一慢两个指针能够判断出链表是否存在环路.假设两个指针相遇之前slow走了s步,则fast走了2s步,并且fast已经在长度

leetcode 【 Linked List Cycle II 】 python 实现

公司和学校事情比较多,隔了好几天没刷题,今天继续刷起来. 题目: Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Follow up:Can you solve it without using extra space? 代码:oj 测试通过 Runtime: 596 ms 1 # Definition for singly-linked list. 2

[C++]LeetCode: 73 Linked List Cycle II

题目: Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Follow up: Can you solve it without using extra space? 思路: 可以参考 LeetCode: 73 Linked List Cycle. 使用快慢两个指针,首先先判断链表是否存在环,如果存在,从相遇点开始,还有另外一个从链表头开始,同时移动一步,

LeetCode | 0141. Linked List Cycle环形链表【Python】

LeetCode 0141. Linked List Cycle环形链表[Easy][Python][双指针] 题目 英文题目地址 Given a linked list, determine if it has a cycle in it. To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked lis

LeetCode(141): Linked List Cycle

Linked List Cycle: Given a linked list, determine if it has a cycle in it. Follow up: Can you solve it without using extra space? 题意:判断一个链表中是否存在环. 思路:(参考别人的做法)采用"快慢指针"检查链表是否含有环.即让一个指针一次走一步,另一个指针一次走两步,如果链表中含有环,快的指针会再次和慢的指针相遇. 代码: public boolean h