442. 数组中重复的数据
[案例需求]
[思路分析一, 原地哈希]
- 同剑指Offer.03题目基本一致;
- 原地哈希是依靠数组建立起index到nums[index]的映射, 从而可以很方便的根据数组的index得到固定的值;
- 注意, 本题目中, 数字的有效范围在 [1, n] ;
- 由于数组中的index是从0开始的, 所以我们的数组为: nums[0] =1, nums[1] = 2, 即 nums[index] = index + 1;
nums[index] 应该放置的位置为 int targetIndex = nums[index] - 1;
[代码实现]
class Solution {
public List<Integer> findDuplicates(int[] nums) {
//原地哈希
// 对应的值为 nums[index] = index+1;
// index = 0, nums[index] = index + 1 = 1 = num[0]
List<Integer> list = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
while(i + 1 != nums[i]){
swap(nums, i, nums[i] - 1);
int targetIndex = nums[i] - 1; //理应待在的地方
if(nums[i] == nums[nums[i] - 1]){
break;
}
}
}
for(int i = 0; i < nums.length; i++){
if(i != nums[i] - 1)list.add(nums[i]);
}
return list;
}
public void swap(int[] nums, int left, int right){
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
[思路分析二, 标记法]
- 遍历这个数组, 我们把遇到的数-1, 作为数组的下标, 并把这个下标处的数变为负数
- 因为nums数组中数字从1到n, 如果数字不重复, 下标肯定是不同的!!!
- 如果遍历到了某个下标时, 这个数已经是负数了, 那肯定就是重复的了
class Solution {
public List<Integer> findDuplicates(int[] nums) {
//标记法
List<Integer> list = new ArrayList<>();
//index 处为 nums[index] - 1;
// nums[index] 的是索引为 index + 1;
for(int i = 0; i < nums.length; i++){
int index = Math.abs(nums[i]) - 1; //把遍历到的数字-1 作为下标(打标记的位置下标),
//另外, 我们不关心遍历到的数字是否被打上标记, 我们只关心遍历结束, 所以对 nums[i]取了绝对值
if(nums[index] < 0){
// nums[index]处不是重复的数,
//而是说有另外的两个数是重复的, 他倆映射的索引位置是nums[index]这个数,
// nums[index] 为负数, 说明是有重复了
list.add(Math.abs(index + 1));
}else{
nums[index] = -nums[index];
}
}
return list;
}
}
如果我们是遍历重复三次, 重复n次的某个数应该如何求解 ?
- 基本思路类似, 都是打标记法(把遍历到的数作为数组的下标), 区别在于如何打标记的策略;
lt- 268. 丢失的数字
[案例需求]
[思路分析一, 排序后遍历查找]
[代码实现]
// //先排序, 再检查差 > 1的数
class Solution {
public int missingNumber(int[] nums) {
Arrays.sort(nums);
int len = nums.length;
if(nums[0] != 0)return 0;
for(int i = 1; i < len; i++){
if(nums[i] - nums[i - 1] > 1)return nums[i - 1] + 1;
}
return len;
}
}
[思路分析二, 原地哈希]
[代码实现]
class Solution {
public int missingNumber(int[] nums) {
//原地哈希
int len = nums.length;
for(int i = 0; i < nums.length; i++){
int targetIndex = nums[i];
if(i != targetIndex && nums[i] < len)
swap(nums, i--, targetIndex);
}
for(int i = 0; i < len; i++){
if(nums[i] != i)
return i;
}
return len;
}
public void swap(int[] nums, int left, int right){
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
其他解法待补充: dbc
[思路分析三, 位运算法]
class Solution {
public int missingNumber(int[] nums) {
int n = nums.length;
int ans = 0;
for (int i = 0; i <= n; i++) ans ^= i;
for (int i : nums) ans ^= i;
return ans;
}
}