【每天学习一点算法 2026/04/30】寻找重复数

每天学习一点算法 2026/04/30

题目:寻找重复数

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

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

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

作者:LeetCode

链接:https://leetcode.cn/leetbook/read/top-interview-questions-hard/xwz4lj/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  1. 二分查找

    首先我们来分析一下,假设我们的 m 是重复数

    1 ~ m-1 范围中的数都是唯一的,那么这个范围中的任意一个数 i 一定满足:小于等于 i 的数字个数 count 是小于等于 i 的。

    m ~ n 范围中的数因为存在重复数 m,那么这个范围中的任意一个数 i 一定满足:小于等于 i 的数字个数 count 是大于 i 的。

    有点抽象我们以 nums = [3,1,3,4,2] 为例:

    • m = 3

    • 1 ~ 2 范围内有 1 和 2 两个数他们 count 分别是 1 和 2,满足上面的规律。

    • 3 ~ 4 范围内有 3 和 4 两个数他们 count 分别是 4 和 5,满足上面的规律。

    那么我们就可以根据这个规律在 1 ~ n 范围进行二分查找,找到第一个 count 大于它自身的数字就是重复数字。

    typescript 复制代码
    function findDuplicate(nums: number[]): number {
      let left = 1, right = nums.length - 1
      let res = 0
      while (left <= right) {
        const mid = Math.floor((left + right) / 2)
        let count = 0
        for (let i = 0; i < nums.length; i++) {
          if (nums[i] <= mid) count++
        }
    
        if (count > mid) {
          right = mid - 1
          res = mid
        } else {
          left = mid + 1
        }
      }
    
      return res
    };
  2. 快慢指针

    我们如果根据数组建立一个链表,使他的下一个节点在数组中的索引等于当前元素值。

    nums = [1,3,4,2,2] 为例:

    • 第一个节点值为:1
    • 第二个节点值为:下标为 1 的 3
    • 第三个节点值为:下标为 3 的 2
    • 第四个节点值为:下标为 2 的 4
    • 第五个节点值为:下标为 4 的 2

    此时出现了重复的节点表示这个链表是有环的,只有存在有重复数字这样生成的链表一定就会有环,而环的入口 2 就是重复的数字。

    这个问题就变成了寻找链表环的入口的问题,我们可以使用快慢指针,快指针每次移动两步,慢指针每次移动一步,根据 Floyd 判圈算法 两个指针一定会相遇。

    假设环的长度是 len,从起点到环的入口步数是 a,入口到相遇位置的步数是 b,从相遇位置回到入口的步数是 c。

    首先 len = b + c

    两指针相遇时,慢指针走了 a + b 步,快指针走了 2(a + b) 步。

    因为两指针相遇时,快指针一定会比慢指针多走若干圈,假设时 x 圈

    那么快指针走的步数也可以表示成:a + b + x * len

    于是就有了: 2(a + b) = a + b + x * len

    a = x * len - b = (x - 1) * len + c

    根据这个公式:如果两个指针一个从快指针出发一个从相遇点出发,当一个指针走了 a 步到达起点时,另外一个指针刚好也能绕 x - 1 圈后再走 c 步回到入口。

    所以我们需要先利用龟兔赛跑式快慢指针到达相遇点,再移动一个指针至起始点,然后两个指针每次都只移动一步,相遇的节点就是环的入口也就是我们要找的重复数。

    typescript 复制代码
    function findDuplicate(nums: number[]): number {
      let fast = 0, slow = 0
      // 利用 Floyd 判圈移动指针到相遇点
      do {
        fast = nums[nums[fast]]
        slow = nums[slow]
      } while (fast != slow)
    	
      slow = 0 // 将慢指针移动到起始点
      // 同步移动快慢指针直至相遇
      while (fast != slow) {
        slow = nums[slow]
        fast = nums[fast]
      }
      return fast // 返回相遇点指针
    };

    题目来源:力扣(LeetCode)

相关推荐
vibecoding日记5 小时前
双非如何快速入职字节等大厂大模型?真实案例分析:推理优化和投机解码
算法·求职·大模型工程师
yszaygr21387 小时前
Verilog参数化游程编码RLE模块
算法
望易7 小时前
刚设计的大模型架构-双域耦合认知框架
算法·架构
复杂网络11 小时前
多个 Claude Code 与多个 Codex 协同工作:设计与实现方案
算法
HjhIron1 天前
面试常客:字符串算法从入门到进阶
算法·面试
吴佳浩1 天前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹1 天前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术1 天前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望1 天前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法