Subject requirements
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]
Suppose an array of integers of length N, the values of the elements in the array are in the [1,n] interval. What integers in the [1,n] interval of the array do not appear?
Ideas and codes
First of all, you can think of using another temporary array to record the number of occurrences of each element, and the element with zero occurrences does not appear in the array. The code is as follows:
public List<Integer> findDisappearedNumbers(int[] nums) { int[] temp = new int[nums.length + 1]; for (int i = 0; i < nums.length; i++) { temp[nums[i]]++; } List<Integer> result = new ArrayList<>(); for (int i = 1; i < temp.length; i++) { if (temp[i] == 0) { result.add(i); } } return result; }
However, this implementation violates the spatial complexity of O(1) (in this case, the result set is not considered as extra space). So how can we avoid using temporary arrays? In fact, we can use the way of exchanging elements in the original array to transform it into a new ordered array. That is to say, from the far left, every time an element is encountered, it will be prevented to the target location of the element. If element i is encountered at bit 0, the element at position i-1 and the element at position 0 will be exchanged, and whether the new element needs to be exchanged will be judged here. If the current element does not need to be swapped, the pointer moves one bit to the right. A scenario that does not need to be performed means that the current element already appears at the target location.
public List<Integer> findDisappearedNumbers(int[] nums) { int index = 0; while(index < nums.length) { if(nums[index] == nums[nums[index]-1]) { nums[nums[index]-1] = nums[index]; index++; }else{ int tmp = nums[index]; nums[index] = nums[tmp-1]; nums[tmp-1] = tmp; } } List<Integer> result = new ArrayList<Integer>(); for(int i = 0 ; i < nums.length ; i++) { if(nums[i] != i+1) { result.add(i+1); } } return result; }