乐趣区

关于leetcode:LeetCode-142287PHP-快慢指针的进阶题

原文链接:何晓东 博客

环形链表 II

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

为了示意给定链表中的环,咱们应用整数 pos 来示意链表尾连贯到链表中的地位(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。

阐明:不容许批改给定的链表。

起源:力扣(LeetCode)
链接:https://leetcode-cn.com/probl…

解题思路 1

遍历链表,同时将每次的后果放到 map 中,首次遇到反复元素,则间接返回这个元素就行,代码和上一篇文章的相似。

解题思路 2

快慢指针求解:咱们定义两个指针,一快一满。慢指针每次只挪动一步,而快指针每次挪动两步。初始时,慢指针在地位 head,而快指针在地位 head.next。这样一来,如果在挪动的过程中,快指针反过来追上慢指针,就阐明该链表为环形链表。否则快指针将达到链表尾部,该链表不为环形链表。

确定有环形之后,就是推理找到入环点:
咱们应用两个指针,fastslow。它们起始都位于链表的头部。随后,slow 指针每次向后挪动一个地位,而 fast 指针向后挪动两个地位。如果链表中存在环,则 fast 指针最终将再次与 slow 指针在环中相遇。

如下图所示,设链表中环外局部的长度为 aa。slow 指针进入环后,又走了 bb 的间隔与 fast 相遇。此时,fast 指针曾经走完了环的 nn 圈,因而它走过的总间隔为 a + n(b + c) + b = a + (n + 1)b + nc

依据题意,任意时刻,fast 指针走过的间隔都为 slow 指针的 22 倍。因而,咱们有

a + (n + 1)b + nc = 2(a+b) ⟹ a = c + (n − 1)(b + c)

有了 a = c + (n – 1)(b + c) 的等量关系,咱们会发现:从相遇点到入环点的间隔加上 n-1 圈的环长,恰好等于从链表头部到入环点的间隔。

因而,当发现 slowfast 相遇时,咱们再额定应用一个指针 ptr。起始,它指向链表头部;随后,它和 slow 每次向后挪动一个地位。最终,它们会在入环点相遇。

作者:LeetCode-Solution
链接:https://leetcode-cn.com/probl…
起源:力扣(LeetCode)

/**
 * Definition for a singly-linked list.
 * class ListNode {
 *     public $val = 0;
 *     public $next = null;
 *     function __construct($val) {$this->val = $val;}
 * }
 */

class Solution {
    /**
     * @param ListNode $head
     * @return ListNode
     */
    function detectCycle($head) {if($head == null || $head->next == null) return null;
        $fast = $head;
        $slow = $head;

        // 在相遇点跳出循环
        
        while ($fast != null && $fast->next != null) {
            $fast = $fast->next->next;
            $slow = $slow->next;
            if ($fast === $slow) {break;}
        }
        
        // 申明 ptr 指针,步长为 1 的向前走

        $ptr = $head;
        while ($ptr !== $slow) {
            $ptr = $ptr->next;
            $slow = $slow->next;
        }
        // ptr 即为入口

        return $ptr;
    }
}

相似的另外一题是:

寻找反复数

给定一个蕴含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包含 1 和 n),可知至多存在一个反复的整数。假如只有一个反复的整数,找出这个反复的数。

示例 1:

 输出: [1,3,4,2,2]
输入: 2

示例 2:

 输出: [3,1,3,4,2]
输入: 3

阐明:

不能更改原数组(假如数组是只读的)。
只能应用额定的 O(1) 的空间。
工夫复杂度小于 O(n2)。
数组中只有一个反复的数字,但它可能不止反复呈现一次。

起源:力扣(LeetCode)
链接:https://leetcode-cn.com/probl…

解题思路

和下面的快慢指针一样的,只是借助索引将数组设想成链表就能够。

代码
class Solution {

    /**
     * @param Integer[] $nums
     * @return Integer
     */
    function findDuplicate($nums) {
        $slow = 0;
        $fast = 0;
        $slow = $nums[$slow];
        $fast = $nums[$nums[$fast]];
        while($slow != $fast){$slow = $nums[$slow];
            $fast = $nums[$nums[$fast]];
        }
        
        $pre1 = 0;
        $pre2 = $slow;
        while($pre1 != $pre2){$pre1 = $nums[$pre1];
            $pre2 = $nums[$pre2];
        }
        return $pre1;
    }
}

参考链接:

  1. 环形链表 Ⅱ 官网题解

最初恰饭 阿里云全系列产品 / 短信包特惠购买 中小企业上云最佳抉择 阿里云外部优惠券

退出移动版