Given an array nums of n integers where nums[i]
is in the range [1, n]
, return an array of all the integers in the range [1, n]
that do not appear in nums.
Example 1:
Input: nums = [4,3,2,7,8,2,3,1]
Output: [5,6]
Example 2:
Input: nums = [1,1]
Output: [2]
Constraints:
n == nums.length
1 <= n <= 105
1 <= nums[i] <= n
Follow up: Could you do it without extra space and in O(n)
runtime? You may assume the returned list does not count as extra space.
个人思路
- 将每个数换到下标为数值-1的位置上去
- 如果下标上的值不对,则将下标 +1 计入答案
AC
/*
* @lc app=leetcode.cn id=448 lang=cpp
*
* [448] 找到所有数组中消失的数字
*/
// @lc code=start
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
vector<int> res;
for(int i = 0; i < nums.size(); i++)
{
while(nums[i] != nums[nums[i] - 1])
{
swap(nums[i], nums[nums[i] - 1]);
}
}
for(int i = 0; i < nums.size(); i++)
{
if(nums[i] != i + 1)
{
res.emplace_back(i + 1);
}
}
//q:为什么不能将两个循环合并成一个?
//a:因为第一个循环中的swap会导致nums[i]的值发生变化,
// 所以不能在第一个循环中判断nums[i]是否等于i + 1
return res;
}
};
// @lc code=end
看了一眼官方题解
事实上,此题解使用数组来充当哈希表的作用,
换句话说,采用哈希表的思路。
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
int n = nums.size();
for (auto& num : nums) {
int x = (num - 1) % n;
nums[x] += n;
}
vector<int> ret;
for (int i = 0; i < n; i++) {
if (nums[i] <= n) {
ret.push_back(i + 1);
}
}
return ret;
}
};
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize) {
for (int i = 0; i < numsSize; i++) {
int x = (nums[i] - 1) % numsSize;
nums[x] += numsSize;
}
int* ret = malloc(sizeof(int) * numsSize);
*returnSize = 0;
for (int i = 0; i < numsSize; i++) {
if (nums[i] <= numsSize) {
ret[(*returnSize)++] = i + 1;
}
}
return ret;
}
复杂度分析
-
时间复杂度:O(n)。其中 n 是数组 nums 的长度。
-
空间复杂度:O(1)。返回值不计入空间复杂度。
总结
在某些情况下,可以使用数组代替哈希表来实现类似哈希表的功能。
例如,如果我们想要计算一组整数中每个整数出现的次数,可以使用一个长度为最大整数值加一的数组,将整数值作为索引,数组值表示该整数出现的次数。这种方法的时间复杂度为O(n),而哈希表的时间复杂度为O(n)或更高(取决于哈希冲突的情况)。
但是,使用数组代替哈希表也有一些限制。首先,数组大小需要事先确定,如果最大整数值太大,则可能需要占用大量的空间。其次,如果要存储的值不是整数,或者要使用其他操作(例如删除、插入等),则数组可能无法有效地实现哈希表的所有功能。
因此,在实现哈希表时,应该根据需要选择最适合的数据结构,而不是盲目地使用数组或哈希表。