力扣hot100 —— 寻找重复数(快慢指针法)

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

解题思路:

// 把数组索引为0的元素当成链表的头节点

        // 索引为0的元素的值为1, 表示头节点的下一个节点的索引为1, 即数组中的3

        // 再下一个节点的索引为3, 即为第一个2

        // 再下一个节点的索引为2, 即为4

        // 再下一个节点的索引为4, 即为第二个2

        // 再下一个节点的索引为2, 即为4

        // 此时形成了一个环

        // 而形成环的原因是下一节点的索引一致, 即为重复的数字

代码解读:

        // 第一阶段:快慢指针从起点出发,快指针每次移动两步,慢指针每次移动一步,直到它们相遇。相遇点证明链表中存在环。

        // 第二阶段:将慢指针重置到起点,然后快慢指针同时每次移动一步,直到它们再次相遇。相遇点就是环的入口,即重复的数字。

        // 快指针和慢指针相遇时,慢指针走了 L + D 步,快指针走了 L + D + nC 步(n 是快指针在环内多走的圈数)。

因为快指针的速度是慢指针的两倍,所以:
2(L + D) = L + D + nC
=> L + D = nC
=> L = nC - D

        // 将慢指针重置到起点,快指针保持在相遇点。

        // 慢指针从起点走 L 步,会到达环的入口。

        // 快指针从相遇点走 L 步,相当于走 nC - D 步(因为 L = nC - D)。

        // 由于快指针已经在环内,走 nC - D 步后,它会回到环的入口。

        // 因此,快慢指针会在环的入口相遇。

class Solution {
public:
    int findDuplicate(vector& nums) {  
        int fast = 0, slow = 0;
        // 检测环
        do {
            fast = nums[nums[fast]]; // 快指针移动两步
            slow = nums[slow];       // 慢指针移动一步
        } while (fast != slow);

        // 找到环的入口
        slow = 0;
        while (fast != slow) {
            fast = nums[fast]; // 快指针移动一步
            slow = nums[slow]; // 慢指针移动一步
        }
        return slow;
    }
};

你可能感兴趣的:(力扣hot100,leetcode,算法,数据结构,快慢指针)