Find All Numbers Disappeared in an Array LT448
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]
Idea 1. HashMap to store (num, count) pair, then loop from 1 to N if any number's count is 0 (or not 1 and not 2).
Time complexity: O(N)
Space complexity: O(N)
1 class Solution { 2 public List<Integer> findDisappearedNumbers(int[] nums) { 3 Map<Integer, Integer> counter = new HashMap<>(); 4 5 for(int num: nums) { 6 counter.put(num, counter.getOrDefault(num, 0) + 1); 7 } 8 9 List<Integer> result = new ArrayList<>(); 10 for(int i = 1; i <= nums.length; ++i) { 11 int count = counter.getOrDefault(i, 0); 12 if(count == 0) { 13 result.add(i); 14 } 15 } 16 17 return result; 18 } 19 }
Idea 2. Modify the array and move nums[i] to nums[nums[i]-1], if there is already a nums[i] in the right place, it means duplicates, replace the current position with -1, in the end loop the array find out the missing i+1 with nums[i] = -1.
Time complexity: O(N)
Space complexity: O(1)
1 class Solution { 2 private void swap(int[] nums, int i, int j) { 3 int temp = nums[i]; 4 nums[i] = nums[j]; 5 nums[j] = temp; 6 } 7 public List<Integer> findDisappearedNumbers(int[] nums) { 8 for(int i = 0; i < nums.length; ++i) { 9 while(nums[i] != nums[nums[i]-1]) { 10 swap(nums, i, nums[i]-1); 11 } 12 } 13 14 List<Integer> result = new ArrayList<>(); 15 for(int i = 0; i < nums.length; ++i) { 16 if(nums[i] != i+1) { 17 result.add(i+1); 18 } 19 } 20 21 return result; 22 } 23 }
Idea 3. Instead of in-place swapping, the key question is whehter the element exists or not, no swapping, for each element nums[i], we mark the occurence by change the sign of nums[nums[i]-1] = -nums[nums[i] -1], if the destination element(nums[dest-1]) is negative, it means dest occurs in the array. Note the negative index by changing the sign, don't forget to use Math.abs(nums[i]). Then return the positive ones in the result list. To restore the array, just change the sign for negative elements.
Time complexity: O(N)
Space complexity: O(1)
1 class Solution { 2 public List<Integer> findDisappearedNumbers(int[] nums) { 3 for(int i = 0; i < nums.length; ++i) { 4 int dest = Math.abs(nums[i]) - 1; 5 if(nums[dest] > 0) { 6 nums[dest] = -nums[dest]; 7 } 8 } 9 10 List<Integer> result = new ArrayList<>(); 11 for(int i = 0; i < nums.length; ++i) { 12 if(nums[i] > 0) { 13 result.add(i+1); 14 } 15 } 16 17 return result; 18 } 19 }
Idea 3.b Add N to the element, instead of changing the sign,
Note ==, the range, N is included
1 class Solution { 2 public List<Integer> findDisappearedNumbers(int[] nums) { 3 int N = nums.length; 4 for(int i = 0; i < nums.length; ++i) { 5 int dest = (nums[i] - 1)%N; 6 if(nums[dest] <= N) { 7 nums[dest] += N; 8 } 9 } 10 11 List<Integer> result = new ArrayList<>(); 12 for(int i = 0; i < nums.length; ++i) { 13 if(nums[i] <= N) { 14 result.add(i+1); 15 } 16 } 17 18 return result; 19 } 20 }