[LeetCode] 448、找到所有数组中消失的数字

题目描述

给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。找到所有在 [1, n] 范围之间没有出现在数组中的数字。(要求 O ( n ) + O ( 1 ) O(n) + O(1) O(n)+O(1)

输入:[4,3,2,7,8,2,3,1]
输出:[5,6]

解题思路

和《剑指offer》上的类似题目不太一样,此题比较有技巧性,不太好想。

  • 哈希表:这种计数题肯定可以用哈希表解决,但是这里不满足空间复杂度要求。

  • 桶排序(推荐):由于数组的元素取值范围是 [1, N],我们可以利用“一个萝卜一个坑”的原理,在输入数组本身以某种方式标记已访问过的数字,然后再找到缺失的数字。

    • 遍历输入数组的每个元素一次。
    • 我们将把 |nums[i]|-1 索引位置的元素标记为负数。即nums[|nums[i]|-1] * -1。(标记)
    • 然后遍历数组,若当前数组元素 nums[i] 为负数,说明我们在数组中存在数字 i+1

    实际上相当于利用正负号构建了一个简易的哈希表,用来存储每个数字的状态,非常巧妙!

    进阶:若将题目要求改为数组中每个元素出现的可能次数是 n 次,求出数组中出现此次为偶数(奇数)次的元素(出现 0 次也算偶数次)。

    解答:将所有正数作为数组下标,置对应数组值为相反数。那么,仍为正数的位置即为出现偶数次(未出现是0次,也是偶数次)数字。

  • 奇技淫巧:看看就好,技巧性太强。

参考代码

class Solution {
     
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
     
        int length = nums.size();
        if(length == 0)
            return  vector<int>();
        
        vector<int> res;
        for(int i = 0; i < length; i++){
     
            int num = abs(nums[i]);
            nums[num - 1] = -abs(nums[num - 1]);  // 标记(要注意防止重复标记,这里用if改写也可以)
        }
        
        for(int i = 0; i < length; i++){
     
            if(nums[i] > 0)
                res.push_back(i+1);
        }
        
        return res;
    }
    
};

你可能感兴趣的:(算法(UVa,+,LeetCode,+,OJ,+,……))