LeetCode-287. 寻找重复数
题目来源
287. 寻找重复数
题目详情
给定一个包含 n + 1
个整数的数组 nums
,其数字都在 1
到 n
之间(包括 1
和 n
),可知至少存在一个重复的整数。
假设 nums
只有 一个重复的整数 ,找出 这个重复的数 。
你设计的解决方案必须不修改数组 nums
且只用常量级 O(1)
的额外空间。
示例 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
提示:
1 <= n <= 105
nums.length == n + 1
1 <= nums[i] <= n
nums
中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次
进阶:
- 如何证明
nums
中至少存在一个重复的数字? - 你可以设计一个线性级时间复杂度
O(n)
的解决方案吗?
题解分析
解法一:排序遍历
- 本题最简单的解法就是对数组进行从小到大排序,再遍历数组判断某个数字是否出现了多次。
- 在遍历数组的时候,除了使用比较法,也可以利用位异或的知识。因为如果两个相邻的元素相同,那前面元素的异或结果接连与这两个元素进行异或的结果其实与异或之前是相同的。
class Solution {
public int findDuplicate(int[] nums) {
int n = nums.length;
Arrays.sort(nums);// 对数组排序
int prepre = 0, pre = 0;
for(int i=0; i
解法二:二分法
- 这里可以换一个角度思考问题。因为这个数组很特殊,它里面的元素的范围都在[1,n]之间,所以重复的元素必然也出现在[1,n]之间。
- 可以利用以上的性质,对于一个元素i,记数组中所有小于等于i的元素个数为cnt[i]。这个cnt[i]与重复的元素是存在一些关系的:假设重复的元素为target,在重复元素之前的i,它的cnt[i]必然小于等于i,而在重复元素之后的i,它的cnt[i]必然大于i,而且cnt数组也存在递增的关系。
- 比如对于一个输入数组:[1,3,4,2,2],它的cnt数组和i的关系如下:
- 示例中重复的整数是 2,我们可以看到 [1,1] 中的数满足cnt[i]≤i,[2,4] 中的数满足cnt[i]>i 。
- 如果知道 cnt[] 数组随数字 i 逐渐增大具有单调性(即 target 前 cnt[i]≤i,target 后 cnt[i]>i),那么我们就可以直接利用二分查找来找到重复的数。
class Solution {
public int findDuplicate(int[] nums) {
int n = nums.length;
int left = 1, right = n-1;
int ans = 0;
while(left <= right){// 小于等于并不是小于
int mid = (left + right) >> 1;
int cnt = 0;
// 计算小于等于当前mid的元素个数
for(int i=0; i
解法三:二进制
class Solution {
public int findDuplicate(int[] nums) {
int n = nums.length;
int intmaxbit = 32;
int bits = 32;
// 求出n的最高位为1的位数
while(((n-1) >> 32) == 0){
bits -= 1;
}
int ans = 0;
// 求数组各元素的第bit位为1的个数
for(int bit=0; bit 0)
y += ((i & (1 << bit)) != 0 ? 1 : 0);
}
if(x > y){
ans |= (1 << bit);
}
}
return ans;
}
}