1.题目
题目地址(448. 找到所有数组中消失的数字 - 力扣(LeetCode))
https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array/
题目描述
给你一个含 n
个整数的数组 nums
,其中 nums[i]
在区间 [1, n]
内。请你找出所有在 [1, n]
范围内但没有出现在 nums
中的数字,并以数组的形式返回结果。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1] 输出:[5,6]
示例 2:
输入:nums = [1,1] 输出:[2]
提示:
n == nums.length
1 <= n <= 105
1 <= nums[i] <= n
进阶:你能在不使用额外空间且时间复杂度为 O(n)
的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。
2.题解
2.1 哈希表
思路
哈希表存储所有出现过的数即可
代码
- 语言支持:C++
C++ Code:
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
int n = nums.size();
unordered_map<int, int> mp;
for(int num: nums){
if(mp.count(num)){
mp[num]++;
} else{
mp.emplace(num, 1);
}
}
vector<int> ans;
for(int i = 1; i <= n; i++){
if(!mp.count(i)){
ans.push_back(i);
}
}
return ans;
}
};
复杂度分析
令 n 为数组长度。
- 时间复杂度:\(O(n)\)
- 空间复杂度:\(O(n)\)
2.2 索引-值
思路
这里比如像某个1-n的数出现了, 我们可以另外用一个数组,一个哈希表来存储他的出现信息;
那我们是否能使用原数组nums来存储出现过数组的信息呢?
注意到数组下标在0-(n-1)中浮动,而数的值为 1-n, 那我们可不可以用数组下标记录所有出现过的值呢?该使用什么标记呢?
我们这里考虑到所有出现的数都在1-n, 如果某个数 i 出现了, 那我们就令nums[i-1] += n, 使其超出n(进行了标记), i-1是因为数和下标差值为1
为何如此标记呢? 因为我们后面还需要用到 nums[i]的值, 就需要还原它, 如何还原呢?
对于所有nums[i] ∈ [1,n], 如果有被标记的数,也就是多了一个n; 如果理解为绕圈,也就是多绕了一圈回来, 对于绕圈问题, 我们直接 % n 即可解决
这也是我们为何选择 +n 而不是选择加其他值的原因
如何判断是否被标记了呢?
在下一次遍历数组时,找到所有值 <= n 的nums[i]即可, 对应的数即为 下标 + 1 = i + 1
代码
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
int n = nums.size();
for(int i = 0; i < n; i++){
int x = (nums[i] - 1) % n;
nums[x] += n; // 用索引0-(n-1)存储出现过的1-n的数, 差值为1
}
vector<int> ans;
for(int i = 0; i < n; i++){
if(nums[i] <= n && nums[i] >= 1){
ans.push_back(i + 1); // 索引和实际值差1
}
}
return ans;
}
};
复杂度分析
令 n 为数组长度。
- 时间复杂度:\(O(n)\)
- 空间复杂度:\(O(n)\)