LeetCode 287 寻找重复数字

题目

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

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

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

示例 1:

复制代码
输入:nums = [1,3,4,2,2]
输出:2

示例 2:

复制代码
输入:nums = [3,1,3,4,2]
输出:3

示例 3 :

复制代码
输入:nums = [3,3,3,3,3]
输出:3

思路解析

实际上最简单的做法就是一次遍历即可,用Set维护,看是否出现过,这样很容易写,但是要额外的空间花销,时间空间都是O(n)

还有更省空间的做法,就是我们把nums当作链表来维护

数组:nums = [1,3,4,2,2]

我们把:索引 0 -> nums[0] 索引 1 -> nums[1] ...

理解为:

0 → nums[0] 1 → nums[1]

即:

i -> nums[i]

那么这个数组就变成:

0 → 1 → 3 → 2 → 4 → 2 → 4 → 2 ...

你会发现:

数字 2 出现重复

图结构中就形成了一个环

那么就可用链表找循环入口思路解决了

第一步:找相遇点(判断是否有环)

慢指针一次走一步

快指针一次走两步

如果存在环:

fast == slow

必然会相遇


第二步:找环入口

数学证明结论:

相遇后,把 slow 放回起点

slow 和 fast 每次走一步

再次相遇的地方就是环入口

环入口 = 重复数字

为什么第二次相遇一定是入口?(核心数学推导)

设:

a = 起点到环入口距离 b = 环入口到相遇点距离 c = 环剩余部分

当第一次相遇时:

slow 走了 a + b fast 走了 2(a + b)

因为 fast 比 slow 多走一圈:

2(a + b) = a + b + k(b + c)

化简得:

a = k(b + c) - b

可得:

a = c + (k-1)(b+c)

说明:

从起点走 a 步

等价于从相遇点走 c 步

而 c 正是:

相遇点到环入口的距离

因此:

slow 从头走 fast 从相遇点走

他们一定在入口相遇

代码

java 复制代码
class Solution {
    public int findDuplicate(int[] nums) {

        // 慢指针:每次走一步
        int slow = 0;

        // 快指针:每次走两步
        int fast = 0;

        // 第一阶段:找到相遇点
        // do-while 是因为必须先走一步
        // 不能直接比较 0 == 0
        do {
            // slow 走一步
            slow = nums[slow];

            // fast 走两步
            fast = nums[nums[fast]];

        } while (fast != slow);  // 相遇说明进入环

        // 第二阶段:寻找环入口
        // 将 slow 放回起点
        slow = 0;

        // slow 和 fast 同速前进
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }

        // 再次相遇的位置就是环入口
        // 也就是重复数字
        return slow;
    }
}
相关推荐
paeamecium1 小时前
【PAT甲级真题】- Student List for Course (25)
数据结构·c++·算法·list·pat考试
Book思议-1 小时前
【数据结构】栈与队列全方位对比 + C 语言完整实现
c语言·数据结构·算法··队列
SteveSenna1 小时前
项目:Trossen Arm MuJoCo
人工智能·学习·算法
NAGNIP1 小时前
一文搞懂CNN经典架构-DenseNet!
算法·面试
道法自然|~2 小时前
BugCTF黄道十二宫
算法·密码学
WHS-_-20223 小时前
Python 算法题学习笔记一
python·学习·算法
沉鱼.443 小时前
第六届题目
算法
黑眼圈子3 小时前
总结一下用Java做算法的常用类和方法
java·开发语言·算法
apcipot_rain3 小时前
天梯赛练习集 时间规划 限时复盘 中档题详解(L1-6~L2-4)
算法
再卷也是菜3 小时前
第一章、线性代数(2)高斯消元法
线性代数·算法