原题链接
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
示例 2:
输入:nums = [3,1,3,4,2]
输出:3
示例 3:
输入:nums = [1,1]
输出:1
示例 4:
输入:nums = [1,1,2]
输出:1
提示:
2 <= n <= 3 * 104
nums.length == n + 1
1 <= nums[i] <= n
nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次
进阶:
如何证明 nums 中至少存在一个重复的数字?
你可以在不修改数组 nums 的情况下解决这个问题吗?
你可以只用常量级 O(1) 的额外空间解决这个问题吗?
你可以设计一个时间复杂度小于 O(n2) 的解决方案吗?
Related Topics 数组 双指针 二分查找
1052 0
class Solution {
public int findDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (set.contains(nums[i])) {
return nums[i];
}
set.add(nums[i]);
}
return 0;
}
}
分查找的思路是先猜一个数(有效范围 [left…right] 里位于中间的数 mid),然后统计原始数组中 小于等于 mid 的元素的个数 cnt:
class Solution {
public int findDuplicate(int[] nums) {
int left = 1, right = nums.length - 1;
while (left < right) {
int count = 0;
int mid = (left + right) / 2;
for (int num : nums) {
if (num <= mid) {
count++;
}
}
// 小于等于 4 的个数如果严格大于 4 个
// 此时重复元素一定出现在 [1, 4] 区间里
if (count > mid) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}
参考:
使用二分法查找一个有范围的整数(结合抽屉原理)
类似 算法—LeetCode 142. 环形链表 II, 相当于寻找环的入口,
因为数组中元素值的范围都在 1-n 内, 所以可以把数组当成对链表的一种描述, 数组里的每一个元素的值表示链表的下一个节点的索引, 如示例1中的[1, 3, 4, 2, 2]
把数组索引为0的元素当成链表的头节点
索引为0的元素的值为1, 表示头节点的下一个节点的索引为1, 即数组中的3
再下一个节点的索引为3, 即为第一个2
再下一个节点的索引为2, 即为4
再下一个节点的索引为4, 即为第二个2
再下一个节点的索引为2, 即为4
此时形成了一个环
这里 fast=fast.next.next 相当于 fast = nums[nums[fast]] 向前推进两步
class Solution {
public int findDuplicate(int[] nums) {
int fast = 0, slow = 0;
while (true) {
fast = nums[nums[fast]];
slow = nums[slow];
if (fast == slow) break;
}
slow = 0;
while (fast != slow) {
fast = nums[fast];
slow = nums[slow];
}
return slow;
}
}
参考: 287.寻找重复数 前端灵魂画师图解快慢指针