You are given an array of n unique integer numbers 0 <= x_i < 2 * n. Print all integers 0 <= x < 2 * n that are not present in this array.
Example:
find_missing([0]) = [1]
find_missing([0, 2, 4]) = [1, 3, 5] # because all numbers are [0, 1, 2, 3, 4, 5]
find_missing([]) = []
find_missing([0, 1, 4, 5]) = [2, 3, 6, 7] # because all numbers are [0, 1, 2, 3, 4, 5, 6, 7]
Quirks are about requirements:
Time complexity O(n) - BUT there should be some fixed constant C independent of size of input such that every element of array is written/read < C times, so radix sorting the array is a no go.
Space complexity O(1) - you may modify the initial array, BUT sorted(initial_array) must equal sorted(array_after_executing_program) AND you can't store integers outside range [0, 2n) in this array (imagine that it's an array of uint32_t).
I saw a lot of complex solutions, but then I found this:
public void printNotInArr(int[] arr) {
if(arr == null)
return null;
int len = arr.length;
int max = 2 * len;
for(int i = 0; i < len; i++) {
System.out.println(max - arr[i] - 1);
}
}
I believe that is the best solution, but I am not sure. I would like to know why that would NOT work.
1 Answer 1
As @LasseV.Karlsen pointed out, [0,3] is a simple counter-example that shows how that solution doesn't work. This, however, is a pretty simple solution (in Python):
def show_missing(l):
n = len(l)
# put numbers less than n into the proper slot
for i in range(0,n):
while l[i]<n and l[i]!=i:
j = l[i]
l[i] = l[j]
l[j] = j
for i in range(0,n):
if l[i]!=i:
print('Missing %s'%i)
# put numbers greater than n into the proper slot
for i in range(0,n):
while l[i]>=n and l[i]!=i+n:
j = l[i]
l[i] = l[j-n]
l[j-n] = j
for i in range(0,n):
if l[i]!=i+n:
print('Missing %s'%(i+n))
The idea is simple. We first rearrange the elements so that every value j that is less than n is stored at index j. We can then go through the array and easily pick out the ones below n that are missing.
We then rearrange the elements so that every value j that is greater than or equal to n is stored at index j-n. Again, we can go through the array and easily pick out the ones greater than or equal to n that are missing.
Since only a couple of local variables are used, the O(1) space complexity is satisfied.
Because of the nested loops, the O(n) time complexity is a little harder to see, but it isn't too hard to show that we never swap more than n elements, since one new element is put into its proper place with each swap.
Since we've only swapped elements of the array, the requirement that all the original elements are still in the array is also satisfied.
-
Can you explain why you first do numbers less than N, then numbers bigger than N? and in second loop, why "l[i]!=i+n" and not "l[i]!=i"user3259176– user32591762016年04月10日 20:25:19 +00:00Commented Apr 10, 2016 at 20:25
-
@user117325: We can't do both the larger and the smaller numbers at the same time because there would be conflicts. For example if l==[0,2].Vaughn Cato– Vaughn Cato2016年04月10日 20:28:11 +00:00Commented Apr 10, 2016 at 20:28
-
@user117325: In the second loop we are only considering values >= n.
n
is stored at index 0,n+1
is stored at index 1, etc. So that's why we're checking to see ifl[i]!=l[i+n]
.Vaughn Cato– Vaughn Cato2016年04月10日 20:32:28 +00:00Commented Apr 10, 2016 at 20:32 -
The code by @YvesDaoust (above) does the same thing regarding the O(n) swap, but does not do it into two parts (less than N, bigger than N). Is there another example that would cause the conflict you describe? His solution might be missing thatuser3259176– user32591762016年04月10日 21:19:53 +00:00Commented Apr 10, 2016 at 21:19
-
1@user117325: I don't think that answer is valid, since it relies on extending the original array.Vaughn Cato– Vaughn Cato2016年04月10日 21:34:22 +00:00Commented Apr 10, 2016 at 21:34
0, 3
. You'll get3, 0
back, clearly it doesn't output the missing numbers at all.