LeetCode 448 Find All Numbers Disappeared in an Array

Problem:

Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.

Find all the elements of [1, n] inclusive that do not appear in this array.

Could you do it without extra space and in O(n) runtime? You may assume the returned list does not count as extra space.

Example:

Input:
[4,3,2,7,8,2,3,1]

Output:
[5,6]

Summary:

长度为n的整形数组a中的所有数大于等于1,小于等于n,其中可能包含重复两次的数字。

输出[1, n]中不存在于数组a中的数字集合。

Solution:

1. 首先想到的方法是用map创建Hash表,key为数组中出现的数字,value为出现次数,再寻找哪个数字出现0次。

 1 class Solution {
 2 public:
 3     vector<int> findDisappearedNumbers(vector<int>& nums) {
 4         int len = nums.size(), maxNum = -1;
 5         sort(nums.begin(), nums.end());
 6         map<int, int> m;
 7         vector<int> res;
 8         
 9         for (int i = 0; i < len; i++) {
10             m[nums[i]]++;
11             maxNum = maxNum < nums[i] ? nums[i] : maxNum;
12         }
13         
14         for (int i = 1; i <= len; i++) {
15             if (!m[i]) {
16                 res.push_back(i);
17             }
18         }
19         
20         return res;
21     }
22 };

但题目中要求不开数组标记,故这个方法不可行。

2. 不消耗其余空间的做法,首先想到的是将数组排序,用一个变量k记录下一个需要查找的[1, n]中的数字,将不存在于数组中的数字存下来。

需要注意的出现重复数字时的处理。

 1 class Solution {
 2 public:
 3     vector<int> findDisappearedNumbers(vector<int>& nums) {
 4         int len = nums.size();
 5         sort(nums.begin(), nums.end());
 6         vector<int> res;
 7         
 8         int k = 1;
 9         for (int i = 0; i < len; i++) {
10             if (k != nums[i]) {
11                 while (k < nums[i]) {
12                     res.push_back(k++);
13                 }
14             }
15             
16             if (i < len - 1 && nums[i] == nums[i + 1]) {
17                 i++;
18             }
19             
20             k++;
21         }
22         
23         while (k <= len) {
24             res.push_back(k++);
25         }
26         
27         return res;
28     }
29 };

但因为有排序,时间复杂度为O(nlogn),不满足题目中的O(n),故这种方法仍不可行。

3. 由于题目中有数组中所有数字都大于等于1且小于等于n,而n为数组长度这一条件。所以可以以数组下标作为索引标记哪些数字出现过,标记方法为将出现数字对应下标的数字标为负数。

  1. 计算出数组中出现的数字x的下标形式,则下表为index = |x| - 1,可将数组a中得a[index]标为负数来标记数字x出现在数组中
  2. 若数组中某数字已为负数,说明该数字在数组中出现过
  3. 最终遍历数组,若a[i]为正数,表明数字 i + 1在数组中没有出现过。

这种方法仅遍历两次数组即可完成,切不用消耗其余空间。

 1 class Solution {
 2 public:
 3     vector<int> findDisappearedNumbers(vector<int>& nums) {
 4         int len = nums.size();
 5         vector<int> res;
 6         for (int i = 0; i < len; i++) {
 7             int index = abs(nums[i]) - 1;
 8             if (nums[index] > 0) {
 9                 nums[index] *= -1;
10             }
11         }
12         
13         for (int i = 0; i < len; i++) {
14             if (nums[i] > 0) {
15                 res.push_back(i + 1);
16             }
17         }
18         
19         return res;
20     }
21 };
原文地址:https://www.cnblogs.com/VickyWang/p/6232635.html