The idea of this algorithm is to:
public List<Integer> findDisappearedNumbers(int[] nums) {
/*
0 1 2 3 4 5 6 7 - positions
[4,3,2,7,8,2,3,1] - input array
^
starts with position 0 and swap with the position where it belongs
4<->7
4 goes to the 3rd (array starts with 0) position and 7 from the 3rd position goes to the 0th position.
[7,3,2,4,8,2,3,1]
Now put 7 in the 6th position where it belongs
7<->3 (0th and 6th positions)
[3,3,2,4,8,2,7,1]
3<->2 (0th and 2nd positions)
[2,3,3,4,8,2,7,1]
2<->3 (0th and 1st)
[3,2,3,4,8,2,7,1]
0th position is taken by 3. It should be put in the 2nd position but it's already taken by 3 which is correct. It's a duplicate, so skip it and check the next index.
1st position already has 2 which is correct. Move on to the next index.
2nd position already has 3 which is correct. Move on to the next index.
3nd position already has 4 which is correct. Move on to the next index.
5th position has 8 and 7th position doesn't have it, so swapping them.
8<->1
[3,2,3,4,1,2,7,8]
Swapping 1 on the 4th position and 3 on the 0th position to put the 1 in the right place.
3<->1
[1,2,3,4,3,2,7,8]
At this point all elements are either in the right place or cannot be swapped as the target position already has the right element (duplicated elements).
*/
List<Integer> missing = new ArrayList<>();
if (nums == null || nums.length == 0) return missing;
int i=0;
int seen = 0;
while (seen < nums.length) {
if (nums[i] == i+1) {
i = (i+1) % nums.length;
seen++;
} else {
int j = nums[i] - 1;
if (nums[i] == nums[j]) {
i = (i+1) % nums.length;
seen++;
} else {
int tmp = nums[j];
nums[j] = nums[i];
nums[i] = tmp;
}
}
}
/*
Compare
[0,1,2,3,4,5,6,7]
to
[1,2,3,4,3,2,7,8]
and add missing elements to the result.
*/
for (int j=0; j<nums.length; j++) {
if (nums[j] != j+1) missing.add(j+1);
}
return missing;
}