zoukankan      html  css  js  c++  java
  • [LeetCode] 142. 环形链表 II

    题目链接 : https://leetcode-cn.com/problems/linked-list-cycle-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
    解释:链表中没有环。
    

    进阶:
    你是否可以不用额外空间解决此题?

    思路:

    思路一: 哈希, 空间复杂度(O(n))

    这个很好考虑, 把遍历过的节点记录,当发现遍历的节点下一个节点遍历过, 返回它

    def detectCycle(self, head):
            """
            :type head: ListNode
            :rtype: ListNode
            """
            lookup = set()
            p = head
            while p:
                lookup.add(p)
                if p.next in lookup:
                    return p.next
                p = p.next
            return None
    

    java

    public class Solution {
        public ListNode detectCycle(ListNode head) {
            Set<ListNode> lookup = new HashSet<>();
            ListNode p = head;
            while (p != null) {
                lookup.add(p);
                if (lookup.contains(p.next)) return p.next;
                p = p.next;
            }
            return null;
        }
    }
    

    思路二 : 快慢指针

    说一下算法思路:

    1. 先用快慢指针, 找到他们相遇点(如果存在环)
    2. 再重新从链表头开始, 以及步骤1的相遇点, 两个位置一起走, 再次相遇就是环的入口

    证明:

    有三个节点需要注意: 起始节点(head), 环的入口节点(输出结果), 相遇的节点(快慢指针求的)

    我们要证明 : 初始点到环的入口的步数 等于 相遇点到环入口的步数

    我们令, 初始点到入口为 s, 入口到相遇点 m, 环的周长为 r

    我们只需证明: s == r - m

    首先我们假设,慢指针走了 k 步到相遇点, 那么快指针就是 2k 步,所以我们有 2k - k = nr k = nr(慢指针还没到环,快指针已经转了好几圈)

    还有, s = k - m

    得 : s = nr - m ==> s == (n - 1) r + (r - m)

    得证!

    class Solution(object):
        def detectCycle(self, head):
            """
            :type head: ListNode
            :rtype: ListNode
            """
            if not head or not head.next : return 
            # 快慢指针
            slow = head
            fast = head
            # 重新开始
            start = head
            while fast and fast.next:
                slow = slow.next
                fast = fast.next.next
                # 找到相遇点
                if slow == fast:
                    while slow != start:
                        slow = slow.next
                        start = start.next
                    return slow
            return None
    

    java

    public class Solution {
        public ListNode detectCycle(ListNode head) {
            if (head == null || head.next == null) return null;
            ListNode slow = head;
            ListNode fast = head;
            ListNode start = head;
            while (fast != null && fast.next != null) {
                slow = slow.next;
                fast = fast.next.next;
                if (slow == fast) {
                    while (start != slow) {
                        slow = slow.next;
                        start = start.next;
                    }
                    return slow;
                }
            }
            return null;
        }
    }
    

    相关题型: 141. 环形链表

  • 相关阅读:
    HDU 5791 Two (DP)
    POJ 1088 滑雪 (DPor记忆化搜索)
    LightOJ 1011
    POJ 1787 Charlie's Change (多重背包 带结果组成)
    HDU 5550 Game Rooms (ccpc2015 K)(dp)
    HDU 5542 The Battle of Chibi (ccpc 南阳 C)(DP 树状数组 离散化)
    HDU 5543 Pick The Sticks (01背包)
    HDU 5546 Ancient Go (ccpc2015南阳G)
    NB-IoT的DRX、eDRX、PSM三个模式 (转载,描述的简单易懂)
    MQTT 嵌入式端通讯协议解析(转)
  • 原文地址:https://www.cnblogs.com/powercai/p/11245996.html
Copyright © 2011-2022 走看看