友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

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

提示:

  • 1 <= n <= 105

  • nums.length == n + 1

  • 1 <= nums[i] <= n

  • nums只有一个整数 出现 两次或多次,其余整数均只出现 一次

进阶:

  • 如何证明 nums 中至少存在一个重复的数字?

  • 你可以设计一个线性级时间复杂度 \(O(n)\) 的解决方案吗?

思路分析

题目要求“不能修改数组”和“O(1)的空间复杂度”,就比较难办了。可以利用 142. 环形链表 II中 龟兔赛跑找环的思路来解决:

0287 02

这里应该有一副这样的图片:

0287 10

这张图也不够完美,没有把计算公式写出来。

如果抛开题目要求的“不能修改数组”和“O(1)的空间复杂度”要求,有更多解法:

  1. 不考虑空间复杂度,可以用 Set 来求解

  2. 如果可以修改数组,则原地交换(把 nums[i] 挪到 nums[nums[i]] 上)。

    0287 01
上图就是 Cyclic Sort 循环排序
  • 一刷

  • 二刷

  • 三刷

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
 * Runtime: 0 ms, faster than 100.00% of Java online submissions for Find the Duplicate Number.
 * Memory Usage: 42.8 MB, less than 5.09% of Java online submissions for Find the Duplicate Number.
 *
 * Copy from: https://leetcode.com/problems/find-the-duplicate-number/solution/[Find the Duplicate Number - LeetCode]
 *
 * @author D瓜哥 · https://www.diguage.com
 * @since 2020-01-05 22:52
 */
public int findDuplicate(int[] nums) {
    int tortoise = nums[0];
    int hare = nums[0];
    do {
        tortoise = nums[tortoise];
        hare = nums[nums[hare]];
    } while (tortoise != hare);

    int pointer1 = nums[0];
    int pointer2 = hare;

    while (pointer1 != pointer2) {
        pointer1 = nums[pointer1];
        pointer2 = nums[pointer2];
    }
    return pointer1;
}

/**
 * Runtime: 95 ms, faster than 5.83% of Java online submissions for Find the Duplicate Number.
 *
 * Memory Usage: 37.8 MB, less than 37.29% of Java online submissions for Find the Duplicate Number.
 */
public int findDuplicateBruteForce(int[] nums) {
    for (int i = 0; i < nums.length - 1; i++) {
        for (int j = i + 1; j < nums.length; j++) {
            if (nums[i] == nums[j]) {
                return nums[i];
            }
        }
    }
    return -1;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
/**
 * @author D瓜哥 · https://www.diguage.com
 * @since 2024-09-13 22:05:18
 */
public int findDuplicate(int[] nums) {
  int slow = 0;
  int fast = 0;
  do {
    slow = nums[slow];
    fast = nums[fast];
    fast = nums[fast];
  } while(slow != fast);
  slow = 0;
  while (slow != fast) {
    slow = nums[slow];
    fast = nums[fast];
  }
  return slow;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-10-17 21:53:03
 */
public int findDuplicate(int[] nums) {
  // 利用快慢指针判断链表是否有环的思路,找到快慢指针的汇合点
  int slow = 0, fast = 0;
  do {
    slow = nums[slow];
    fast = nums[fast];
    fast = nums[fast];
  } while (slow != fast);

  // 从链表头开始遍历,直到相遇,则就是重复元素
  fast = 0;
  while (slow != fast) {
    slow = nums[slow];
    fast = nums[fast];
  }
  return slow;
}