目录
题目描述
解法一:抽屉原理
思路一
思路二
解法二:位运算
解题总结
给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次。找到所有出现两次的元素。你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗?
示例:
输入:
[4,3,2,7,8,2,3,1]
输出:
[2,3]
仔细观察题目描述 1 ≤ a[i] ≤ n (n为数组长度),数组里的不同的元素类别可视为抽屉。数组个数视之为苹果
1.从头到位遍历数组如果发现 i==(a[i]-1),说明a[i]处的数据是对的,直接跳过。
2. i!=(a[i]-1)的话再判断a[a[i]-1]==a[i]是否成立,成立的话说明a[i]出现过2次,直接放入结果
3.a[a[i]-1]!=a[i]的话交换下标a[i]-1和i处的数据,交换之后可能导致a[i]-1>i,这时i可以不用继续向前移动,a[i]-1<=i的话要继续移动i
class Solution {
public List findDuplicates(int[] nums) {
List ans = new ArrayList();
int n = nums.length;
for( int i =0;i curVal-1 时,说明curVal-1索引处的值被处理过,这里直接交换
// 当i
把下标index和下标nums[index]处的数位互换,数组重复或则之前已经有序的下标结束循环
class Solution {
public int findDuplicate(int[] nums) {
int index = 0;
while(index < nums.length){
if(nums[index]-1!= index){
//这种情况构成循环所以要额外判断
if(nums[index] == nums[nums[index]-1]){
return nums[index];
}
//index之前的下标已经有序,再次出现小于的元素可认为是重复
if(nums[index]-1 < index){
return nums[index];
}
swap(nums,nums[index]-1,index);
}else {
index++;
}
}
return 0;
}
private void swap(int[] nums,int i,int j){
int tmep = nums[i];
nums[i] = nums[j];
nums[j] = tmep;
}
}
[1,n]的二进制中的各位是1的数次是固定的,比如
输入:nums = [1, 3, 4, 2, 2] 输出:2
[1, 4]的位数如下
从上面我们可以知道,如果第i位1的总数x > y,那么重复数的第i位就是1;
class Solution {
public int findDuplicate(int[] nums) {
int n = nums.length, ans = 0;
int bit_max = 31;
while (((n - 1) >> bit_max) == 0) {
bit_max -= 1;
}
for (int bit = 0; bit <= bit_max; ++bit) {
int x = 0, y = 0;
for (int i = 0; i < n; ++i) {
//把nums[1]-nums[n]的第bit位为1的挨个计算一遍
if ((nums[i] & (1 << bit)) != 0) {
x += 1;
}
//把1-n的第bit位为1的挨个计算一遍
if (i >= 1 && ((i & (1 << bit)) != 0)) {
y += 1;
}
}
if (x > y) {
ans |= 1 << bit;
}
}
return ans;
}
}
掌握解题的思想之后代码只是实现思想的工具,前期需要大量储备各种思想
另外本题还有二分和快慢指针的求解方法
LeetCode287之寻找重复数(相关话题:二分查找,快慢指针)_leetcode寻找重复记录_数据与后端架构提升之路的博客-CSDN博客
LeetCode645错误的集合
(参考题解-理解透彻版)
LeetCode448找到所有数组中消失的数字
LeetCode442数组中重复的数据