Insert a smallest possible positive integer into an array of unique integers [duplicate]Find the Smallest Integer Not in a ListIs there an O(n) integer sorting algorithm?How to insert an item into an array at a specific index (JavaScript)?How to sort an array of integers correctlyAlgorithm: efficient way to remove duplicate integers from an arrayFind the Smallest Integer Not in a ListGet all unique values in a JavaScript array (remove duplicates)Compare two integer arrays with same lengthEasy interview question got harder: given numbers 1..100, find the missing number(s) given exactly k are missingFind the row representing the smallest integer in row wise sorted matrixGiven an array of positive and negative integers, re-arrange it so that you have positive integers on one end and negative integers on otherfinding smallest positive integer missing from an unsorted array, hard edition
Can the pre-order traversal of two different trees be the same even though they are different?
Print the new site header
How can I prevent a user from copying files on another hard drive?
How can I restore a master database from its bak file?
Examples of protocols that are insecure when run concurrently
Am I legally required to provide a (GPL licensed) source code even after a project is abandoned?
Kelvin type connection
Can a character learn spells from someone else's spellbook and then sell it?
How Hebrew Vowels Work
Why was New Asgard established at this place?
Is the author of the Shu"t HaRidvaz the same one as the one known to be the rebbe of the Ariza"l?
Are there examples of rowers who also fought?
Is there a polite way to ask about one's ethnicity?
How to write a nice frame challenge?
Justifying Affordable Bespoke Spaceships
What mathematical theory is required for high frequency trading?
Is there any way to revive my Sim?
What could be the physiological mechanism for a biological Geiger counter?
Are intrusions within a foreign embassy considered an act of war?
In the US, can a former president run again?
Scaling an object to change its key
Setting up the trap
How to make all magic-casting innate, but still rare?
How much steel armor can you wear and still be able to swim?
Insert a smallest possible positive integer into an array of unique integers [duplicate]
Find the Smallest Integer Not in a ListIs there an O(n) integer sorting algorithm?How to insert an item into an array at a specific index (JavaScript)?How to sort an array of integers correctlyAlgorithm: efficient way to remove duplicate integers from an arrayFind the Smallest Integer Not in a ListGet all unique values in a JavaScript array (remove duplicates)Compare two integer arrays with same lengthEasy interview question got harder: given numbers 1..100, find the missing number(s) given exactly k are missingFind the row representing the smallest integer in row wise sorted matrixGiven an array of positive and negative integers, re-arrange it so that you have positive integers on one end and negative integers on otherfinding smallest positive integer missing from an unsorted array, hard edition
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
This question already has an answer here:
Find the Smallest Integer Not in a List
28 answers
I am trying to tackle this interview question: given an array of unique positive integers, find the smallest possible number to insert into it so that every integer is still unique. The algorithm should be in O(n) and the additional space complexity should be constant. Assigning values in the array to other integers is allowed.
For example, for an array [5, 3, 2, 7], output should be 1. However for [5, 3, 2, 7, 1], the answer should then be 4.
My first idea is to sort the array, then go through the array again to find where the continuous sequence breaks, but sorting needs more than O(n).
Any ideas would be appreciated!
arrays algorithm big-o
New contributor
maranic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
marked as duplicate by Oleksandr, vivek_23, Bob__, cs95, גלעד ברקן Jun 10 at 23:37
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
|
show 10 more comments
This question already has an answer here:
Find the Smallest Integer Not in a List
28 answers
I am trying to tackle this interview question: given an array of unique positive integers, find the smallest possible number to insert into it so that every integer is still unique. The algorithm should be in O(n) and the additional space complexity should be constant. Assigning values in the array to other integers is allowed.
For example, for an array [5, 3, 2, 7], output should be 1. However for [5, 3, 2, 7, 1], the answer should then be 4.
My first idea is to sort the array, then go through the array again to find where the continuous sequence breaks, but sorting needs more than O(n).
Any ideas would be appreciated!
arrays algorithm big-o
New contributor
maranic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
marked as duplicate by Oleksandr, vivek_23, Bob__, cs95, גלעד ברקן Jun 10 at 23:37
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
1
No, but finding that max value should be in O(n) and need constant space complexity
– maranic
Jun 10 at 12:43
1
@mnm We need to "find the smallest possible number to insert into it so that every integer is still unique". For[5,3,2,7], the smallest possible number is 1, but for the second array,1,2,3are all present, so the next possible smalles number is 4.
– maranic
Jun 10 at 13:06
1
@SurakofVulcan The only rule is that the values in the array should remain positive integers.
– maranic
Jun 10 at 13:11
1
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
– גלעד ברקן
Jun 10 at 13:16
2
@גלעדברקן: no. The space of the input data structure doesn't count.
– Yves Daoust
Jun 10 at 13:38
|
show 10 more comments
This question already has an answer here:
Find the Smallest Integer Not in a List
28 answers
I am trying to tackle this interview question: given an array of unique positive integers, find the smallest possible number to insert into it so that every integer is still unique. The algorithm should be in O(n) and the additional space complexity should be constant. Assigning values in the array to other integers is allowed.
For example, for an array [5, 3, 2, 7], output should be 1. However for [5, 3, 2, 7, 1], the answer should then be 4.
My first idea is to sort the array, then go through the array again to find where the continuous sequence breaks, but sorting needs more than O(n).
Any ideas would be appreciated!
arrays algorithm big-o
New contributor
maranic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
This question already has an answer here:
Find the Smallest Integer Not in a List
28 answers
I am trying to tackle this interview question: given an array of unique positive integers, find the smallest possible number to insert into it so that every integer is still unique. The algorithm should be in O(n) and the additional space complexity should be constant. Assigning values in the array to other integers is allowed.
For example, for an array [5, 3, 2, 7], output should be 1. However for [5, 3, 2, 7, 1], the answer should then be 4.
My first idea is to sort the array, then go through the array again to find where the continuous sequence breaks, but sorting needs more than O(n).
Any ideas would be appreciated!
This question already has an answer here:
Find the Smallest Integer Not in a List
28 answers
arrays algorithm big-o
arrays algorithm big-o
New contributor
maranic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
maranic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
edited Jun 10 at 13:28
Yassin Hajaj
15.1k83062
15.1k83062
New contributor
maranic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked Jun 10 at 12:24
maranicmaranic
544
544
New contributor
maranic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
maranic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
marked as duplicate by Oleksandr, vivek_23, Bob__, cs95, גלעד ברקן Jun 10 at 23:37
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
marked as duplicate by Oleksandr, vivek_23, Bob__, cs95, גלעד ברקן Jun 10 at 23:37
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
1
No, but finding that max value should be in O(n) and need constant space complexity
– maranic
Jun 10 at 12:43
1
@mnm We need to "find the smallest possible number to insert into it so that every integer is still unique". For[5,3,2,7], the smallest possible number is 1, but for the second array,1,2,3are all present, so the next possible smalles number is 4.
– maranic
Jun 10 at 13:06
1
@SurakofVulcan The only rule is that the values in the array should remain positive integers.
– maranic
Jun 10 at 13:11
1
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
– גלעד ברקן
Jun 10 at 13:16
2
@גלעדברקן: no. The space of the input data structure doesn't count.
– Yves Daoust
Jun 10 at 13:38
|
show 10 more comments
1
No, but finding that max value should be in O(n) and need constant space complexity
– maranic
Jun 10 at 12:43
1
@mnm We need to "find the smallest possible number to insert into it so that every integer is still unique". For[5,3,2,7], the smallest possible number is 1, but for the second array,1,2,3are all present, so the next possible smalles number is 4.
– maranic
Jun 10 at 13:06
1
@SurakofVulcan The only rule is that the values in the array should remain positive integers.
– maranic
Jun 10 at 13:11
1
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
– גלעד ברקן
Jun 10 at 13:16
2
@גלעדברקן: no. The space of the input data structure doesn't count.
– Yves Daoust
Jun 10 at 13:38
1
1
No, but finding that max value should be in O(n) and need constant space complexity
– maranic
Jun 10 at 12:43
No, but finding that max value should be in O(n) and need constant space complexity
– maranic
Jun 10 at 12:43
1
1
@mnm We need to "find the smallest possible number to insert into it so that every integer is still unique". For
[5,3,2,7], the smallest possible number is 1, but for the second array, 1,2,3 are all present, so the next possible smalles number is 4.– maranic
Jun 10 at 13:06
@mnm We need to "find the smallest possible number to insert into it so that every integer is still unique". For
[5,3,2,7], the smallest possible number is 1, but for the second array, 1,2,3 are all present, so the next possible smalles number is 4.– maranic
Jun 10 at 13:06
1
1
@SurakofVulcan The only rule is that the values in the array should remain positive integers.
– maranic
Jun 10 at 13:11
@SurakofVulcan The only rule is that the values in the array should remain positive integers.
– maranic
Jun 10 at 13:11
1
1
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
– גלעד ברקן
Jun 10 at 13:16
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
– גלעד ברקן
Jun 10 at 13:16
2
2
@גלעדברקן: no. The space of the input data structure doesn't count.
– Yves Daoust
Jun 10 at 13:38
@גלעדברקן: no. The space of the input data structure doesn't count.
– Yves Daoust
Jun 10 at 13:38
|
show 10 more comments
8 Answers
8
active
oldest
votes
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
Loop over the array and multiply A[ |A[i]| - 1 ] by -1 for |A[i]| < array length. Loop a second time and output (the index + 1) for the first cell not negative or (array length + 1) if they are all marked. This takes advantage of the fact that there could not be more than (array length) unique integers in the array.
Because the input space doesn’t count. Compare things like quickselect. If you could count this as O(n) space, then any actual auxiliary O(n) space wouldn’t change the space complexity…
– Ry-♦
Jun 10 at 13:48
@Ry but we are reusing the space assigned to the input for the solution. That means the solution implementation is using O(n) space.
– גלעד ברקן
Jun 10 at 13:49
1
Downvoters care to explain?
– גלעד ברקן
Jun 10 at 14:13
1
Very good indeed. Maybe indicate that you assume indexing from 0
– Damien
Jun 10 at 14:53
add a comment |
My attempt:
The array A is assumed 1-indexed. We call an active value one that is nonzero and does not exceed n.
Scan the array until you find an active value, let
A[i] = k(if you can't find one, stop);While
A[k]is active,- Move
A[k]tokwhile clearingA[k];
- Move
Continue from
iuntil you reach the end of the array.
After this pass, all array entries corresponding to some integer in the array are cleared.
- Find the first nonzero entry, and report its index.
E.g.
[5, 3, 2, 7], clear A[3]
[5, 3, 0, 7], clear A[2]
[5, 0, 0, 7], done
The answer is 1.
E.g.
[5, 3, 2, 7, 1], clear A[5],
[5, 3, 2, 7, 0], clear A[1]
[0, 3, 2, 7, 0], clear A[3],
[0, 3, 0, 7, 0], clear A[2],
[0, 0, 0, 7, 0], done
The answer is 4.
The behavior of the first pass is linear because every number is looked at once (and immediately cleared), and i increases regularly.
The second pass is a linear search.
A= [5, 3, 2, 7, 1]
N= len(A)
print(A)
for i in range(N):
k= A[i]
while k > 0 and k <= N:
A[k-1], k = 0, A[k-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 0, 7, 0]
[0, 0, 0, 7, 0]
[0, 0, 0, 7, 0]
Update:
Based on גלעד ברקן's idea, we can mark the array elements in a way that does not destroy the values. Then you report the index of the first unmarked.
print(A)
for a in A:
a= abs(a)
if a <= N:
A[a-1]= - A[a-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, -1]
[5, 3, -2, 7, -1]
[5, -3, -2, 7, -1]
[5, -3, -2, 7, -1]
[-5, -3, -2, 7, -1]
In my example I don't. Where do you see that ? If the array was[7, 3, 2, 5, 1], the 1 would clear it.
– Yves Daoust
Jun 10 at 14:24
1
My answer performs the same idea, which is to mark seen values, just avoids using an additional pointer.
– גלעד ברקן
Jun 10 at 14:25
1
@YassinHajaj: the answer is 1, as correctly reported by my solution.
– Yves Daoust
Jun 10 at 14:26
I don't understand the downvotes, this works well and is O(n)
– aka.nice
Jun 10 at 15:12
@aka.nice: yep. On second thoughts, it is easier to mark the array elements non-destructively like גלעד ברקן, playing wiht the sign, so that you just do with two forward loops.
– Yves Daoust
Jun 10 at 15:17
|
show 2 more comments
I will use 1-based indexing.
The idea is to reuse input collection and arrange to swap integer i at ith place if its current position is larger than i. This can be performed in O(n).
Then on second iteration, you find the first index i not containing i, which is again O(n).
In Smalltalk, implemented in Array (self is the array):
firstMissing
self size to: 1 by: -1 do: [:i |
[(self at: i) < i] whileTrue: [self swap: i with: (self at: i)]].
1 to: self size do: [:i |
(self at: i) = i ifFalse: [^i]].
^self size + 1
So we have two loops in O(n), but we also have another loop inside the first loop (whileTrue:). So is the first loop really O(n)?
Yes, because each element will be swapped at most once, since they will arrive at their right place. We see that the cumulated number of swap is bounded by array size, and the overall cost of first loop is at most 2*n, the total cost incuding last seatch is at most 3*n, still O(n).
You also see that we don't care to swap case of (self at: i) > i and: [(self at:i) <= self size], why? Because we are sure that there will be a smaller missing element in this case.
A small test case:
| trial |
trial := (1 to: 100100) asArray shuffled first: 100000.
self assert: trial copy firstMissing = trial sorted firstMissing.
This works only if the size of the input is at least as large as the maximal value in the array.
– fjardon
Jun 10 at 14:43
@fjardon No. I swap indexiand indexself at: ionly if(self at: i) < i. I thus never write pastself size(and could not in Smalltalk, such buffer overrun would cause an exception).
– aka.nice
Jun 10 at 15:00
add a comment |
You could do the following.
- Find the maximum (m), sum of all elements (s), number of elements (n)
- There are m-n elements missing, their sum is q = sum(1..m) - s - there is a closed-form solution for the sum
- If you are missing only one integer, you're done - report q
- If you are missing more than one (m-n), you realize that the sum of the missing integers is q, and at least one of them will be smaller than q/(m-n)
- You start from the top, except you will only take into account integers smaller than q/(m-n) - this will be the new m, only elements below that maximum contribute to the new s and n. Do this until you are left with only one missing integer.
Still, this may not be linear time, I'm not sure.
add a comment |
The key points:
The value you search will be < N+1.
All items greater than N can be ignored
Items are unique so every item less or equal to N has its unique place.
The algorithm:
Go over the array,
if a[i] > N replace with -1, continue to i+1.
if a[i]==i or a[i] == -1, continue to i+1
if a[i] != i swap a[i] with a[a[i]] and don't increment i (this puts the item in its right place).
Now go over the array again and search for the first -1.
The complexity is O(N) since in every step you put one item in its place.
add a comment |
EDIT: you should use the candidate plus half the input size as a pivot to reduce the constant factor here – see Daniel Schepler’s comment – but I haven’t had time to get it working in the example code yet.
This isn’t optimal – there’s a clever solution being looked for – but it’s enough to meet the criteria :)
- Define the smallest possible candidate so far: 1.
- If the size of the input is 0, the smallest possible candidate is a valid candidate, so return it.
- Partition the input into < pivot and > pivot (with median of medians pivot, like in quicksort).
- If the size of ≤ pivot is less than pivot itself, there’s a free value in there, so start over at step 2 considering only the < pivot partition.
- Otherwise (when it’s = pivot), the new smallest possible candidate is the pivot + 1. Start over at step 2 considering only the > pivot partition.
I think that works…?
'use strict';
const swap = (arr, i, j) =>
[arr[i], arr[j]] = [arr[j], arr[i]];
;
// dummy pivot selection, because this part isn’t important
const selectPivot = (arr, start, end) =>
start + Math.floor(Math.random() * (end - start));
const partition = (arr, start, end) =>
let mid = selectPivot(arr, start, end);
const pivot = arr[mid];
swap(arr, mid, start);
mid = start;
for (let i = start + 1; i < end; i++)
if (arr[i] < pivot)
mid++;
swap(arr, i, mid);
swap(arr, mid, start);
return mid;
;
const findMissing = arr =>
let candidate = 1;
let start = 0;
let end = arr.length;
for (;;)
if (start === end)
return candidate;
const pivotIndex = partition(arr, start, end);
const pivot = arr[pivotIndex];
if (pivotIndex + 1 < pivot)
end = pivotIndex;
else
//assert(pivotIndex + 1 === pivot);
candidate = pivot + 1;
start = pivotIndex + 1;
;
const createTestCase = (size, max) =>
if (max < size)
throw new Error('size must be < max');
const arr = Array.from(length: max, (_, i) => i + 1);
const expectedIndex = Math.floor(Math.random() * size);
arr.splice(expectedIndex, 1 + Math.floor(Math.random() * (max - size - 1)));
for (let i = 0; i < size; i++)
let j = i + Math.floor(Math.random() * (size - i));
swap(arr, i, j);
return
input: arr.slice(0, size),
expected: expectedIndex + 1,
;
;
for (let i = 0; i < 5; i++)
const test = createTestCase(1000, 1024);
console.log(findMissing(test.input), test.expected);
Or - on an input of length n you know the output is at most n+1, so pivot at n/2 etc. and do a binary search for the output value. Then T(n) = O(n) + T(n/2) so T(n) = O(n).
– Daniel Schepler
Jun 10 at 21:05
@DanielSchepler: I’m not sure what you mean by a binary search compared to what this is already, but n/2 is a better choice of pivot, thanks.
– Ry-♦
Jun 10 at 21:09
You were mentioning median-of-median partition selection. My idea was to partition based on possible output values not partition the list into rough halves "spatially".
– Daniel Schepler
Jun 10 at 21:10
add a comment |
The correct method I almost got on my own, but I had to search for it, and I found it here: https://www.geeksforgeeks.org/find-the-smallest-positive-number-missing-from-an-unsorted-array/
Note: This method is destructive to the original data
Nothing in the original question said you could not be destructive.
I will explain what you need to do now.
The basic "aha" here is that the fist missing number must come within the first N positive numbers, where N is the length of the array.
Once you understand this and realize you can use the values in the array itself as markers, you just have one problem you need to address: Does the array have numbers less than 1 in it? If so we need to deal with them.
Dealing with 0s or negative numbers can be done in O(n) time. Get two integers, one for our current value, and one for the end of the array. As we scan through, if we find a 0 or negative number, we perform a swap using a third integer, with the final value in the array. Then we decrement our end of array pointer. We continue until our current pointer is past the end of the array pointer.
Code example:
while (list[end] < 1)
end--;
while (cur< end)
if (n < 1)
swap(list[cur], list[end]);
while (list[end] < 1)
end--;
Now we have the end of array, and a truncated array. From here we need to see how we can use the array itself. Since all numbers that we care about are positive, and we have a pointer to the position of how many of them there are, we can simply multiply one by -1 to mark that place as present if there was a number in the array there.
e.g. [5, 3, 2, 7, 1] when we read 3, we change it to [5, 3, -2, 7, 1]
Code example:
for (cur = 0; cur <= end; begin++)
if (!(abs(list[cur]) > end))
list[abs(list[cur]) - 1] *= -1;
Now, note: You need to read the absolute value of the integer in the position, because it might be changed to be negative. Also note, if an integer is greater than your end of list pointer, do not change anything as that integer will not matter.
Finally, once you have read all the positive values, iterate through them to find the first one that is currently positive. This place represents your first missing number.
Step 1: Segregate 0 and negative numbers from your list to the right. O(n)
Step 2: Using the end of list pointer iterate through the entire list marking
relevant positions negative. O(n-k)
Step 3: Scan the numbers for the position of the first non-negative number. O(n-k)
Space Complexity: The original list is not counted, I used 3 integers beyond that. So
it is O(1)
One thing I should mention is the list [5, 4, 2, 1, 3] would end up [-5, -4, -2, -1, -3] so in this case, you would choose the first number after the end position of the list, or 6 as your result.
Code example for step 3:
for (cur = 0; cur < end; cur++)
if (list[cur] > 0)
break;
print(cur);
add a comment |
use this algorithm:
A is [5, 3, 2, 7]
1- Define B With Length = A.Length; (O(1))
2- initialize B Cells With 1; (O(n))
3- For Each Item In A:
if (B.Length <= item) then B[Item] = -1 (O(n))
4- The answer is smallest index in B such that B[index] != -1 (O(n))
what's wrong with this solution?!
– Hamed
Jun 11 at 7:52
add a comment |
8 Answers
8
active
oldest
votes
8 Answers
8
active
oldest
votes
active
oldest
votes
active
oldest
votes
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
Loop over the array and multiply A[ |A[i]| - 1 ] by -1 for |A[i]| < array length. Loop a second time and output (the index + 1) for the first cell not negative or (array length + 1) if they are all marked. This takes advantage of the fact that there could not be more than (array length) unique integers in the array.
Because the input space doesn’t count. Compare things like quickselect. If you could count this as O(n) space, then any actual auxiliary O(n) space wouldn’t change the space complexity…
– Ry-♦
Jun 10 at 13:48
@Ry but we are reusing the space assigned to the input for the solution. That means the solution implementation is using O(n) space.
– גלעד ברקן
Jun 10 at 13:49
1
Downvoters care to explain?
– גלעד ברקן
Jun 10 at 14:13
1
Very good indeed. Maybe indicate that you assume indexing from 0
– Damien
Jun 10 at 14:53
add a comment |
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
Loop over the array and multiply A[ |A[i]| - 1 ] by -1 for |A[i]| < array length. Loop a second time and output (the index + 1) for the first cell not negative or (array length + 1) if they are all marked. This takes advantage of the fact that there could not be more than (array length) unique integers in the array.
Because the input space doesn’t count. Compare things like quickselect. If you could count this as O(n) space, then any actual auxiliary O(n) space wouldn’t change the space complexity…
– Ry-♦
Jun 10 at 13:48
@Ry but we are reusing the space assigned to the input for the solution. That means the solution implementation is using O(n) space.
– גלעד ברקן
Jun 10 at 13:49
1
Downvoters care to explain?
– גלעד ברקן
Jun 10 at 14:13
1
Very good indeed. Maybe indicate that you assume indexing from 0
– Damien
Jun 10 at 14:53
add a comment |
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
Loop over the array and multiply A[ |A[i]| - 1 ] by -1 for |A[i]| < array length. Loop a second time and output (the index + 1) for the first cell not negative or (array length + 1) if they are all marked. This takes advantage of the fact that there could not be more than (array length) unique integers in the array.
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
Loop over the array and multiply A[ |A[i]| - 1 ] by -1 for |A[i]| < array length. Loop a second time and output (the index + 1) for the first cell not negative or (array length + 1) if they are all marked. This takes advantage of the fact that there could not be more than (array length) unique integers in the array.
edited Jun 10 at 14:10
answered Jun 10 at 13:21
גלעד ברקןגלעד ברקן
14.2k21646
14.2k21646
Because the input space doesn’t count. Compare things like quickselect. If you could count this as O(n) space, then any actual auxiliary O(n) space wouldn’t change the space complexity…
– Ry-♦
Jun 10 at 13:48
@Ry but we are reusing the space assigned to the input for the solution. That means the solution implementation is using O(n) space.
– גלעד ברקן
Jun 10 at 13:49
1
Downvoters care to explain?
– גלעד ברקן
Jun 10 at 14:13
1
Very good indeed. Maybe indicate that you assume indexing from 0
– Damien
Jun 10 at 14:53
add a comment |
Because the input space doesn’t count. Compare things like quickselect. If you could count this as O(n) space, then any actual auxiliary O(n) space wouldn’t change the space complexity…
– Ry-♦
Jun 10 at 13:48
@Ry but we are reusing the space assigned to the input for the solution. That means the solution implementation is using O(n) space.
– גלעד ברקן
Jun 10 at 13:49
1
Downvoters care to explain?
– גלעד ברקן
Jun 10 at 14:13
1
Very good indeed. Maybe indicate that you assume indexing from 0
– Damien
Jun 10 at 14:53
Because the input space doesn’t count. Compare things like quickselect. If you could count this as O(n) space, then any actual auxiliary O(n) space wouldn’t change the space complexity…
– Ry-♦
Jun 10 at 13:48
Because the input space doesn’t count. Compare things like quickselect. If you could count this as O(n) space, then any actual auxiliary O(n) space wouldn’t change the space complexity…
– Ry-♦
Jun 10 at 13:48
@Ry but we are reusing the space assigned to the input for the solution. That means the solution implementation is using O(n) space.
– גלעד ברקן
Jun 10 at 13:49
@Ry but we are reusing the space assigned to the input for the solution. That means the solution implementation is using O(n) space.
– גלעד ברקן
Jun 10 at 13:49
1
1
Downvoters care to explain?
– גלעד ברקן
Jun 10 at 14:13
Downvoters care to explain?
– גלעד ברקן
Jun 10 at 14:13
1
1
Very good indeed. Maybe indicate that you assume indexing from 0
– Damien
Jun 10 at 14:53
Very good indeed. Maybe indicate that you assume indexing from 0
– Damien
Jun 10 at 14:53
add a comment |
My attempt:
The array A is assumed 1-indexed. We call an active value one that is nonzero and does not exceed n.
Scan the array until you find an active value, let
A[i] = k(if you can't find one, stop);While
A[k]is active,- Move
A[k]tokwhile clearingA[k];
- Move
Continue from
iuntil you reach the end of the array.
After this pass, all array entries corresponding to some integer in the array are cleared.
- Find the first nonzero entry, and report its index.
E.g.
[5, 3, 2, 7], clear A[3]
[5, 3, 0, 7], clear A[2]
[5, 0, 0, 7], done
The answer is 1.
E.g.
[5, 3, 2, 7, 1], clear A[5],
[5, 3, 2, 7, 0], clear A[1]
[0, 3, 2, 7, 0], clear A[3],
[0, 3, 0, 7, 0], clear A[2],
[0, 0, 0, 7, 0], done
The answer is 4.
The behavior of the first pass is linear because every number is looked at once (and immediately cleared), and i increases regularly.
The second pass is a linear search.
A= [5, 3, 2, 7, 1]
N= len(A)
print(A)
for i in range(N):
k= A[i]
while k > 0 and k <= N:
A[k-1], k = 0, A[k-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 0, 7, 0]
[0, 0, 0, 7, 0]
[0, 0, 0, 7, 0]
Update:
Based on גלעד ברקן's idea, we can mark the array elements in a way that does not destroy the values. Then you report the index of the first unmarked.
print(A)
for a in A:
a= abs(a)
if a <= N:
A[a-1]= - A[a-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, -1]
[5, 3, -2, 7, -1]
[5, -3, -2, 7, -1]
[5, -3, -2, 7, -1]
[-5, -3, -2, 7, -1]
In my example I don't. Where do you see that ? If the array was[7, 3, 2, 5, 1], the 1 would clear it.
– Yves Daoust
Jun 10 at 14:24
1
My answer performs the same idea, which is to mark seen values, just avoids using an additional pointer.
– גלעד ברקן
Jun 10 at 14:25
1
@YassinHajaj: the answer is 1, as correctly reported by my solution.
– Yves Daoust
Jun 10 at 14:26
I don't understand the downvotes, this works well and is O(n)
– aka.nice
Jun 10 at 15:12
@aka.nice: yep. On second thoughts, it is easier to mark the array elements non-destructively like גלעד ברקן, playing wiht the sign, so that you just do with two forward loops.
– Yves Daoust
Jun 10 at 15:17
|
show 2 more comments
My attempt:
The array A is assumed 1-indexed. We call an active value one that is nonzero and does not exceed n.
Scan the array until you find an active value, let
A[i] = k(if you can't find one, stop);While
A[k]is active,- Move
A[k]tokwhile clearingA[k];
- Move
Continue from
iuntil you reach the end of the array.
After this pass, all array entries corresponding to some integer in the array are cleared.
- Find the first nonzero entry, and report its index.
E.g.
[5, 3, 2, 7], clear A[3]
[5, 3, 0, 7], clear A[2]
[5, 0, 0, 7], done
The answer is 1.
E.g.
[5, 3, 2, 7, 1], clear A[5],
[5, 3, 2, 7, 0], clear A[1]
[0, 3, 2, 7, 0], clear A[3],
[0, 3, 0, 7, 0], clear A[2],
[0, 0, 0, 7, 0], done
The answer is 4.
The behavior of the first pass is linear because every number is looked at once (and immediately cleared), and i increases regularly.
The second pass is a linear search.
A= [5, 3, 2, 7, 1]
N= len(A)
print(A)
for i in range(N):
k= A[i]
while k > 0 and k <= N:
A[k-1], k = 0, A[k-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 0, 7, 0]
[0, 0, 0, 7, 0]
[0, 0, 0, 7, 0]
Update:
Based on גלעד ברקן's idea, we can mark the array elements in a way that does not destroy the values. Then you report the index of the first unmarked.
print(A)
for a in A:
a= abs(a)
if a <= N:
A[a-1]= - A[a-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, -1]
[5, 3, -2, 7, -1]
[5, -3, -2, 7, -1]
[5, -3, -2, 7, -1]
[-5, -3, -2, 7, -1]
In my example I don't. Where do you see that ? If the array was[7, 3, 2, 5, 1], the 1 would clear it.
– Yves Daoust
Jun 10 at 14:24
1
My answer performs the same idea, which is to mark seen values, just avoids using an additional pointer.
– גלעד ברקן
Jun 10 at 14:25
1
@YassinHajaj: the answer is 1, as correctly reported by my solution.
– Yves Daoust
Jun 10 at 14:26
I don't understand the downvotes, this works well and is O(n)
– aka.nice
Jun 10 at 15:12
@aka.nice: yep. On second thoughts, it is easier to mark the array elements non-destructively like גלעד ברקן, playing wiht the sign, so that you just do with two forward loops.
– Yves Daoust
Jun 10 at 15:17
|
show 2 more comments
My attempt:
The array A is assumed 1-indexed. We call an active value one that is nonzero and does not exceed n.
Scan the array until you find an active value, let
A[i] = k(if you can't find one, stop);While
A[k]is active,- Move
A[k]tokwhile clearingA[k];
- Move
Continue from
iuntil you reach the end of the array.
After this pass, all array entries corresponding to some integer in the array are cleared.
- Find the first nonzero entry, and report its index.
E.g.
[5, 3, 2, 7], clear A[3]
[5, 3, 0, 7], clear A[2]
[5, 0, 0, 7], done
The answer is 1.
E.g.
[5, 3, 2, 7, 1], clear A[5],
[5, 3, 2, 7, 0], clear A[1]
[0, 3, 2, 7, 0], clear A[3],
[0, 3, 0, 7, 0], clear A[2],
[0, 0, 0, 7, 0], done
The answer is 4.
The behavior of the first pass is linear because every number is looked at once (and immediately cleared), and i increases regularly.
The second pass is a linear search.
A= [5, 3, 2, 7, 1]
N= len(A)
print(A)
for i in range(N):
k= A[i]
while k > 0 and k <= N:
A[k-1], k = 0, A[k-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 0, 7, 0]
[0, 0, 0, 7, 0]
[0, 0, 0, 7, 0]
Update:
Based on גלעד ברקן's idea, we can mark the array elements in a way that does not destroy the values. Then you report the index of the first unmarked.
print(A)
for a in A:
a= abs(a)
if a <= N:
A[a-1]= - A[a-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, -1]
[5, 3, -2, 7, -1]
[5, -3, -2, 7, -1]
[5, -3, -2, 7, -1]
[-5, -3, -2, 7, -1]
My attempt:
The array A is assumed 1-indexed. We call an active value one that is nonzero and does not exceed n.
Scan the array until you find an active value, let
A[i] = k(if you can't find one, stop);While
A[k]is active,- Move
A[k]tokwhile clearingA[k];
- Move
Continue from
iuntil you reach the end of the array.
After this pass, all array entries corresponding to some integer in the array are cleared.
- Find the first nonzero entry, and report its index.
E.g.
[5, 3, 2, 7], clear A[3]
[5, 3, 0, 7], clear A[2]
[5, 0, 0, 7], done
The answer is 1.
E.g.
[5, 3, 2, 7, 1], clear A[5],
[5, 3, 2, 7, 0], clear A[1]
[0, 3, 2, 7, 0], clear A[3],
[0, 3, 0, 7, 0], clear A[2],
[0, 0, 0, 7, 0], done
The answer is 4.
The behavior of the first pass is linear because every number is looked at once (and immediately cleared), and i increases regularly.
The second pass is a linear search.
A= [5, 3, 2, 7, 1]
N= len(A)
print(A)
for i in range(N):
k= A[i]
while k > 0 and k <= N:
A[k-1], k = 0, A[k-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 0, 7, 0]
[0, 0, 0, 7, 0]
[0, 0, 0, 7, 0]
Update:
Based on גלעד ברקן's idea, we can mark the array elements in a way that does not destroy the values. Then you report the index of the first unmarked.
print(A)
for a in A:
a= abs(a)
if a <= N:
A[a-1]= - A[a-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, -1]
[5, 3, -2, 7, -1]
[5, -3, -2, 7, -1]
[5, -3, -2, 7, -1]
[-5, -3, -2, 7, -1]
edited Jun 10 at 15:31
answered Jun 10 at 14:12
Yves DaoustYves Daoust
39k82963
39k82963
In my example I don't. Where do you see that ? If the array was[7, 3, 2, 5, 1], the 1 would clear it.
– Yves Daoust
Jun 10 at 14:24
1
My answer performs the same idea, which is to mark seen values, just avoids using an additional pointer.
– גלעד ברקן
Jun 10 at 14:25
1
@YassinHajaj: the answer is 1, as correctly reported by my solution.
– Yves Daoust
Jun 10 at 14:26
I don't understand the downvotes, this works well and is O(n)
– aka.nice
Jun 10 at 15:12
@aka.nice: yep. On second thoughts, it is easier to mark the array elements non-destructively like גלעד ברקן, playing wiht the sign, so that you just do with two forward loops.
– Yves Daoust
Jun 10 at 15:17
|
show 2 more comments
In my example I don't. Where do you see that ? If the array was[7, 3, 2, 5, 1], the 1 would clear it.
– Yves Daoust
Jun 10 at 14:24
1
My answer performs the same idea, which is to mark seen values, just avoids using an additional pointer.
– גלעד ברקן
Jun 10 at 14:25
1
@YassinHajaj: the answer is 1, as correctly reported by my solution.
– Yves Daoust
Jun 10 at 14:26
I don't understand the downvotes, this works well and is O(n)
– aka.nice
Jun 10 at 15:12
@aka.nice: yep. On second thoughts, it is easier to mark the array elements non-destructively like גלעד ברקן, playing wiht the sign, so that you just do with two forward loops.
– Yves Daoust
Jun 10 at 15:17
In my example I don't. Where do you see that ? If the array was
[7, 3, 2, 5, 1], the 1 would clear it.– Yves Daoust
Jun 10 at 14:24
In my example I don't. Where do you see that ? If the array was
[7, 3, 2, 5, 1], the 1 would clear it.– Yves Daoust
Jun 10 at 14:24
1
1
My answer performs the same idea, which is to mark seen values, just avoids using an additional pointer.
– גלעד ברקן
Jun 10 at 14:25
My answer performs the same idea, which is to mark seen values, just avoids using an additional pointer.
– גלעד ברקן
Jun 10 at 14:25
1
1
@YassinHajaj: the answer is 1, as correctly reported by my solution.
– Yves Daoust
Jun 10 at 14:26
@YassinHajaj: the answer is 1, as correctly reported by my solution.
– Yves Daoust
Jun 10 at 14:26
I don't understand the downvotes, this works well and is O(n)
– aka.nice
Jun 10 at 15:12
I don't understand the downvotes, this works well and is O(n)
– aka.nice
Jun 10 at 15:12
@aka.nice: yep. On second thoughts, it is easier to mark the array elements non-destructively like גלעד ברקן, playing wiht the sign, so that you just do with two forward loops.
– Yves Daoust
Jun 10 at 15:17
@aka.nice: yep. On second thoughts, it is easier to mark the array elements non-destructively like גלעד ברקן, playing wiht the sign, so that you just do with two forward loops.
– Yves Daoust
Jun 10 at 15:17
|
show 2 more comments
I will use 1-based indexing.
The idea is to reuse input collection and arrange to swap integer i at ith place if its current position is larger than i. This can be performed in O(n).
Then on second iteration, you find the first index i not containing i, which is again O(n).
In Smalltalk, implemented in Array (self is the array):
firstMissing
self size to: 1 by: -1 do: [:i |
[(self at: i) < i] whileTrue: [self swap: i with: (self at: i)]].
1 to: self size do: [:i |
(self at: i) = i ifFalse: [^i]].
^self size + 1
So we have two loops in O(n), but we also have another loop inside the first loop (whileTrue:). So is the first loop really O(n)?
Yes, because each element will be swapped at most once, since they will arrive at their right place. We see that the cumulated number of swap is bounded by array size, and the overall cost of first loop is at most 2*n, the total cost incuding last seatch is at most 3*n, still O(n).
You also see that we don't care to swap case of (self at: i) > i and: [(self at:i) <= self size], why? Because we are sure that there will be a smaller missing element in this case.
A small test case:
| trial |
trial := (1 to: 100100) asArray shuffled first: 100000.
self assert: trial copy firstMissing = trial sorted firstMissing.
This works only if the size of the input is at least as large as the maximal value in the array.
– fjardon
Jun 10 at 14:43
@fjardon No. I swap indexiand indexself at: ionly if(self at: i) < i. I thus never write pastself size(and could not in Smalltalk, such buffer overrun would cause an exception).
– aka.nice
Jun 10 at 15:00
add a comment |
I will use 1-based indexing.
The idea is to reuse input collection and arrange to swap integer i at ith place if its current position is larger than i. This can be performed in O(n).
Then on second iteration, you find the first index i not containing i, which is again O(n).
In Smalltalk, implemented in Array (self is the array):
firstMissing
self size to: 1 by: -1 do: [:i |
[(self at: i) < i] whileTrue: [self swap: i with: (self at: i)]].
1 to: self size do: [:i |
(self at: i) = i ifFalse: [^i]].
^self size + 1
So we have two loops in O(n), but we also have another loop inside the first loop (whileTrue:). So is the first loop really O(n)?
Yes, because each element will be swapped at most once, since they will arrive at their right place. We see that the cumulated number of swap is bounded by array size, and the overall cost of first loop is at most 2*n, the total cost incuding last seatch is at most 3*n, still O(n).
You also see that we don't care to swap case of (self at: i) > i and: [(self at:i) <= self size], why? Because we are sure that there will be a smaller missing element in this case.
A small test case:
| trial |
trial := (1 to: 100100) asArray shuffled first: 100000.
self assert: trial copy firstMissing = trial sorted firstMissing.
This works only if the size of the input is at least as large as the maximal value in the array.
– fjardon
Jun 10 at 14:43
@fjardon No. I swap indexiand indexself at: ionly if(self at: i) < i. I thus never write pastself size(and could not in Smalltalk, such buffer overrun would cause an exception).
– aka.nice
Jun 10 at 15:00
add a comment |
I will use 1-based indexing.
The idea is to reuse input collection and arrange to swap integer i at ith place if its current position is larger than i. This can be performed in O(n).
Then on second iteration, you find the first index i not containing i, which is again O(n).
In Smalltalk, implemented in Array (self is the array):
firstMissing
self size to: 1 by: -1 do: [:i |
[(self at: i) < i] whileTrue: [self swap: i with: (self at: i)]].
1 to: self size do: [:i |
(self at: i) = i ifFalse: [^i]].
^self size + 1
So we have two loops in O(n), but we also have another loop inside the first loop (whileTrue:). So is the first loop really O(n)?
Yes, because each element will be swapped at most once, since they will arrive at their right place. We see that the cumulated number of swap is bounded by array size, and the overall cost of first loop is at most 2*n, the total cost incuding last seatch is at most 3*n, still O(n).
You also see that we don't care to swap case of (self at: i) > i and: [(self at:i) <= self size], why? Because we are sure that there will be a smaller missing element in this case.
A small test case:
| trial |
trial := (1 to: 100100) asArray shuffled first: 100000.
self assert: trial copy firstMissing = trial sorted firstMissing.
I will use 1-based indexing.
The idea is to reuse input collection and arrange to swap integer i at ith place if its current position is larger than i. This can be performed in O(n).
Then on second iteration, you find the first index i not containing i, which is again O(n).
In Smalltalk, implemented in Array (self is the array):
firstMissing
self size to: 1 by: -1 do: [:i |
[(self at: i) < i] whileTrue: [self swap: i with: (self at: i)]].
1 to: self size do: [:i |
(self at: i) = i ifFalse: [^i]].
^self size + 1
So we have two loops in O(n), but we also have another loop inside the first loop (whileTrue:). So is the first loop really O(n)?
Yes, because each element will be swapped at most once, since they will arrive at their right place. We see that the cumulated number of swap is bounded by array size, and the overall cost of first loop is at most 2*n, the total cost incuding last seatch is at most 3*n, still O(n).
You also see that we don't care to swap case of (self at: i) > i and: [(self at:i) <= self size], why? Because we are sure that there will be a smaller missing element in this case.
A small test case:
| trial |
trial := (1 to: 100100) asArray shuffled first: 100000.
self assert: trial copy firstMissing = trial sorted firstMissing.
answered Jun 10 at 14:41
aka.niceaka.nice
6,94712236
6,94712236
This works only if the size of the input is at least as large as the maximal value in the array.
– fjardon
Jun 10 at 14:43
@fjardon No. I swap indexiand indexself at: ionly if(self at: i) < i. I thus never write pastself size(and could not in Smalltalk, such buffer overrun would cause an exception).
– aka.nice
Jun 10 at 15:00
add a comment |
This works only if the size of the input is at least as large as the maximal value in the array.
– fjardon
Jun 10 at 14:43
@fjardon No. I swap indexiand indexself at: ionly if(self at: i) < i. I thus never write pastself size(and could not in Smalltalk, such buffer overrun would cause an exception).
– aka.nice
Jun 10 at 15:00
This works only if the size of the input is at least as large as the maximal value in the array.
– fjardon
Jun 10 at 14:43
This works only if the size of the input is at least as large as the maximal value in the array.
– fjardon
Jun 10 at 14:43
@fjardon No. I swap index
i and index self at: i only if (self at: i) < i. I thus never write past self size (and could not in Smalltalk, such buffer overrun would cause an exception).– aka.nice
Jun 10 at 15:00
@fjardon No. I swap index
i and index self at: i only if (self at: i) < i. I thus never write past self size (and could not in Smalltalk, such buffer overrun would cause an exception).– aka.nice
Jun 10 at 15:00
add a comment |
You could do the following.
- Find the maximum (m), sum of all elements (s), number of elements (n)
- There are m-n elements missing, their sum is q = sum(1..m) - s - there is a closed-form solution for the sum
- If you are missing only one integer, you're done - report q
- If you are missing more than one (m-n), you realize that the sum of the missing integers is q, and at least one of them will be smaller than q/(m-n)
- You start from the top, except you will only take into account integers smaller than q/(m-n) - this will be the new m, only elements below that maximum contribute to the new s and n. Do this until you are left with only one missing integer.
Still, this may not be linear time, I'm not sure.
add a comment |
You could do the following.
- Find the maximum (m), sum of all elements (s), number of elements (n)
- There are m-n elements missing, their sum is q = sum(1..m) - s - there is a closed-form solution for the sum
- If you are missing only one integer, you're done - report q
- If you are missing more than one (m-n), you realize that the sum of the missing integers is q, and at least one of them will be smaller than q/(m-n)
- You start from the top, except you will only take into account integers smaller than q/(m-n) - this will be the new m, only elements below that maximum contribute to the new s and n. Do this until you are left with only one missing integer.
Still, this may not be linear time, I'm not sure.
add a comment |
You could do the following.
- Find the maximum (m), sum of all elements (s), number of elements (n)
- There are m-n elements missing, their sum is q = sum(1..m) - s - there is a closed-form solution for the sum
- If you are missing only one integer, you're done - report q
- If you are missing more than one (m-n), you realize that the sum of the missing integers is q, and at least one of them will be smaller than q/(m-n)
- You start from the top, except you will only take into account integers smaller than q/(m-n) - this will be the new m, only elements below that maximum contribute to the new s and n. Do this until you are left with only one missing integer.
Still, this may not be linear time, I'm not sure.
You could do the following.
- Find the maximum (m), sum of all elements (s), number of elements (n)
- There are m-n elements missing, their sum is q = sum(1..m) - s - there is a closed-form solution for the sum
- If you are missing only one integer, you're done - report q
- If you are missing more than one (m-n), you realize that the sum of the missing integers is q, and at least one of them will be smaller than q/(m-n)
- You start from the top, except you will only take into account integers smaller than q/(m-n) - this will be the new m, only elements below that maximum contribute to the new s and n. Do this until you are left with only one missing integer.
Still, this may not be linear time, I'm not sure.
answered Jun 10 at 13:43
Surak of VulcanSurak of Vulcan
18418
18418
add a comment |
add a comment |
The key points:
The value you search will be < N+1.
All items greater than N can be ignored
Items are unique so every item less or equal to N has its unique place.
The algorithm:
Go over the array,
if a[i] > N replace with -1, continue to i+1.
if a[i]==i or a[i] == -1, continue to i+1
if a[i] != i swap a[i] with a[a[i]] and don't increment i (this puts the item in its right place).
Now go over the array again and search for the first -1.
The complexity is O(N) since in every step you put one item in its place.
add a comment |
The key points:
The value you search will be < N+1.
All items greater than N can be ignored
Items are unique so every item less or equal to N has its unique place.
The algorithm:
Go over the array,
if a[i] > N replace with -1, continue to i+1.
if a[i]==i or a[i] == -1, continue to i+1
if a[i] != i swap a[i] with a[a[i]] and don't increment i (this puts the item in its right place).
Now go over the array again and search for the first -1.
The complexity is O(N) since in every step you put one item in its place.
add a comment |
The key points:
The value you search will be < N+1.
All items greater than N can be ignored
Items are unique so every item less or equal to N has its unique place.
The algorithm:
Go over the array,
if a[i] > N replace with -1, continue to i+1.
if a[i]==i or a[i] == -1, continue to i+1
if a[i] != i swap a[i] with a[a[i]] and don't increment i (this puts the item in its right place).
Now go over the array again and search for the first -1.
The complexity is O(N) since in every step you put one item in its place.
The key points:
The value you search will be < N+1.
All items greater than N can be ignored
Items are unique so every item less or equal to N has its unique place.
The algorithm:
Go over the array,
if a[i] > N replace with -1, continue to i+1.
if a[i]==i or a[i] == -1, continue to i+1
if a[i] != i swap a[i] with a[a[i]] and don't increment i (this puts the item in its right place).
Now go over the array again and search for the first -1.
The complexity is O(N) since in every step you put one item in its place.
edited Jun 10 at 16:31
answered Jun 10 at 13:43
shuki avrahamshuki avraham
47728
47728
add a comment |
add a comment |
EDIT: you should use the candidate plus half the input size as a pivot to reduce the constant factor here – see Daniel Schepler’s comment – but I haven’t had time to get it working in the example code yet.
This isn’t optimal – there’s a clever solution being looked for – but it’s enough to meet the criteria :)
- Define the smallest possible candidate so far: 1.
- If the size of the input is 0, the smallest possible candidate is a valid candidate, so return it.
- Partition the input into < pivot and > pivot (with median of medians pivot, like in quicksort).
- If the size of ≤ pivot is less than pivot itself, there’s a free value in there, so start over at step 2 considering only the < pivot partition.
- Otherwise (when it’s = pivot), the new smallest possible candidate is the pivot + 1. Start over at step 2 considering only the > pivot partition.
I think that works…?
'use strict';
const swap = (arr, i, j) =>
[arr[i], arr[j]] = [arr[j], arr[i]];
;
// dummy pivot selection, because this part isn’t important
const selectPivot = (arr, start, end) =>
start + Math.floor(Math.random() * (end - start));
const partition = (arr, start, end) =>
let mid = selectPivot(arr, start, end);
const pivot = arr[mid];
swap(arr, mid, start);
mid = start;
for (let i = start + 1; i < end; i++)
if (arr[i] < pivot)
mid++;
swap(arr, i, mid);
swap(arr, mid, start);
return mid;
;
const findMissing = arr =>
let candidate = 1;
let start = 0;
let end = arr.length;
for (;;)
if (start === end)
return candidate;
const pivotIndex = partition(arr, start, end);
const pivot = arr[pivotIndex];
if (pivotIndex + 1 < pivot)
end = pivotIndex;
else
//assert(pivotIndex + 1 === pivot);
candidate = pivot + 1;
start = pivotIndex + 1;
;
const createTestCase = (size, max) =>
if (max < size)
throw new Error('size must be < max');
const arr = Array.from(length: max, (_, i) => i + 1);
const expectedIndex = Math.floor(Math.random() * size);
arr.splice(expectedIndex, 1 + Math.floor(Math.random() * (max - size - 1)));
for (let i = 0; i < size; i++)
let j = i + Math.floor(Math.random() * (size - i));
swap(arr, i, j);
return
input: arr.slice(0, size),
expected: expectedIndex + 1,
;
;
for (let i = 0; i < 5; i++)
const test = createTestCase(1000, 1024);
console.log(findMissing(test.input), test.expected);
Or - on an input of length n you know the output is at most n+1, so pivot at n/2 etc. and do a binary search for the output value. Then T(n) = O(n) + T(n/2) so T(n) = O(n).
– Daniel Schepler
Jun 10 at 21:05
@DanielSchepler: I’m not sure what you mean by a binary search compared to what this is already, but n/2 is a better choice of pivot, thanks.
– Ry-♦
Jun 10 at 21:09
You were mentioning median-of-median partition selection. My idea was to partition based on possible output values not partition the list into rough halves "spatially".
– Daniel Schepler
Jun 10 at 21:10
add a comment |
EDIT: you should use the candidate plus half the input size as a pivot to reduce the constant factor here – see Daniel Schepler’s comment – but I haven’t had time to get it working in the example code yet.
This isn’t optimal – there’s a clever solution being looked for – but it’s enough to meet the criteria :)
- Define the smallest possible candidate so far: 1.
- If the size of the input is 0, the smallest possible candidate is a valid candidate, so return it.
- Partition the input into < pivot and > pivot (with median of medians pivot, like in quicksort).
- If the size of ≤ pivot is less than pivot itself, there’s a free value in there, so start over at step 2 considering only the < pivot partition.
- Otherwise (when it’s = pivot), the new smallest possible candidate is the pivot + 1. Start over at step 2 considering only the > pivot partition.
I think that works…?
'use strict';
const swap = (arr, i, j) =>
[arr[i], arr[j]] = [arr[j], arr[i]];
;
// dummy pivot selection, because this part isn’t important
const selectPivot = (arr, start, end) =>
start + Math.floor(Math.random() * (end - start));
const partition = (arr, start, end) =>
let mid = selectPivot(arr, start, end);
const pivot = arr[mid];
swap(arr, mid, start);
mid = start;
for (let i = start + 1; i < end; i++)
if (arr[i] < pivot)
mid++;
swap(arr, i, mid);
swap(arr, mid, start);
return mid;
;
const findMissing = arr =>
let candidate = 1;
let start = 0;
let end = arr.length;
for (;;)
if (start === end)
return candidate;
const pivotIndex = partition(arr, start, end);
const pivot = arr[pivotIndex];
if (pivotIndex + 1 < pivot)
end = pivotIndex;
else
//assert(pivotIndex + 1 === pivot);
candidate = pivot + 1;
start = pivotIndex + 1;
;
const createTestCase = (size, max) =>
if (max < size)
throw new Error('size must be < max');
const arr = Array.from(length: max, (_, i) => i + 1);
const expectedIndex = Math.floor(Math.random() * size);
arr.splice(expectedIndex, 1 + Math.floor(Math.random() * (max - size - 1)));
for (let i = 0; i < size; i++)
let j = i + Math.floor(Math.random() * (size - i));
swap(arr, i, j);
return
input: arr.slice(0, size),
expected: expectedIndex + 1,
;
;
for (let i = 0; i < 5; i++)
const test = createTestCase(1000, 1024);
console.log(findMissing(test.input), test.expected);
Or - on an input of length n you know the output is at most n+1, so pivot at n/2 etc. and do a binary search for the output value. Then T(n) = O(n) + T(n/2) so T(n) = O(n).
– Daniel Schepler
Jun 10 at 21:05
@DanielSchepler: I’m not sure what you mean by a binary search compared to what this is already, but n/2 is a better choice of pivot, thanks.
– Ry-♦
Jun 10 at 21:09
You were mentioning median-of-median partition selection. My idea was to partition based on possible output values not partition the list into rough halves "spatially".
– Daniel Schepler
Jun 10 at 21:10
add a comment |
EDIT: you should use the candidate plus half the input size as a pivot to reduce the constant factor here – see Daniel Schepler’s comment – but I haven’t had time to get it working in the example code yet.
This isn’t optimal – there’s a clever solution being looked for – but it’s enough to meet the criteria :)
- Define the smallest possible candidate so far: 1.
- If the size of the input is 0, the smallest possible candidate is a valid candidate, so return it.
- Partition the input into < pivot and > pivot (with median of medians pivot, like in quicksort).
- If the size of ≤ pivot is less than pivot itself, there’s a free value in there, so start over at step 2 considering only the < pivot partition.
- Otherwise (when it’s = pivot), the new smallest possible candidate is the pivot + 1. Start over at step 2 considering only the > pivot partition.
I think that works…?
'use strict';
const swap = (arr, i, j) =>
[arr[i], arr[j]] = [arr[j], arr[i]];
;
// dummy pivot selection, because this part isn’t important
const selectPivot = (arr, start, end) =>
start + Math.floor(Math.random() * (end - start));
const partition = (arr, start, end) =>
let mid = selectPivot(arr, start, end);
const pivot = arr[mid];
swap(arr, mid, start);
mid = start;
for (let i = start + 1; i < end; i++)
if (arr[i] < pivot)
mid++;
swap(arr, i, mid);
swap(arr, mid, start);
return mid;
;
const findMissing = arr =>
let candidate = 1;
let start = 0;
let end = arr.length;
for (;;)
if (start === end)
return candidate;
const pivotIndex = partition(arr, start, end);
const pivot = arr[pivotIndex];
if (pivotIndex + 1 < pivot)
end = pivotIndex;
else
//assert(pivotIndex + 1 === pivot);
candidate = pivot + 1;
start = pivotIndex + 1;
;
const createTestCase = (size, max) =>
if (max < size)
throw new Error('size must be < max');
const arr = Array.from(length: max, (_, i) => i + 1);
const expectedIndex = Math.floor(Math.random() * size);
arr.splice(expectedIndex, 1 + Math.floor(Math.random() * (max - size - 1)));
for (let i = 0; i < size; i++)
let j = i + Math.floor(Math.random() * (size - i));
swap(arr, i, j);
return
input: arr.slice(0, size),
expected: expectedIndex + 1,
;
;
for (let i = 0; i < 5; i++)
const test = createTestCase(1000, 1024);
console.log(findMissing(test.input), test.expected);
EDIT: you should use the candidate plus half the input size as a pivot to reduce the constant factor here – see Daniel Schepler’s comment – but I haven’t had time to get it working in the example code yet.
This isn’t optimal – there’s a clever solution being looked for – but it’s enough to meet the criteria :)
- Define the smallest possible candidate so far: 1.
- If the size of the input is 0, the smallest possible candidate is a valid candidate, so return it.
- Partition the input into < pivot and > pivot (with median of medians pivot, like in quicksort).
- If the size of ≤ pivot is less than pivot itself, there’s a free value in there, so start over at step 2 considering only the < pivot partition.
- Otherwise (when it’s = pivot), the new smallest possible candidate is the pivot + 1. Start over at step 2 considering only the > pivot partition.
I think that works…?
'use strict';
const swap = (arr, i, j) =>
[arr[i], arr[j]] = [arr[j], arr[i]];
;
// dummy pivot selection, because this part isn’t important
const selectPivot = (arr, start, end) =>
start + Math.floor(Math.random() * (end - start));
const partition = (arr, start, end) =>
let mid = selectPivot(arr, start, end);
const pivot = arr[mid];
swap(arr, mid, start);
mid = start;
for (let i = start + 1; i < end; i++)
if (arr[i] < pivot)
mid++;
swap(arr, i, mid);
swap(arr, mid, start);
return mid;
;
const findMissing = arr =>
let candidate = 1;
let start = 0;
let end = arr.length;
for (;;)
if (start === end)
return candidate;
const pivotIndex = partition(arr, start, end);
const pivot = arr[pivotIndex];
if (pivotIndex + 1 < pivot)
end = pivotIndex;
else
//assert(pivotIndex + 1 === pivot);
candidate = pivot + 1;
start = pivotIndex + 1;
;
const createTestCase = (size, max) =>
if (max < size)
throw new Error('size must be < max');
const arr = Array.from(length: max, (_, i) => i + 1);
const expectedIndex = Math.floor(Math.random() * size);
arr.splice(expectedIndex, 1 + Math.floor(Math.random() * (max - size - 1)));
for (let i = 0; i < size; i++)
let j = i + Math.floor(Math.random() * (size - i));
swap(arr, i, j);
return
input: arr.slice(0, size),
expected: expectedIndex + 1,
;
;
for (let i = 0; i < 5; i++)
const test = createTestCase(1000, 1024);
console.log(findMissing(test.input), test.expected);
'use strict';
const swap = (arr, i, j) =>
[arr[i], arr[j]] = [arr[j], arr[i]];
;
// dummy pivot selection, because this part isn’t important
const selectPivot = (arr, start, end) =>
start + Math.floor(Math.random() * (end - start));
const partition = (arr, start, end) =>
let mid = selectPivot(arr, start, end);
const pivot = arr[mid];
swap(arr, mid, start);
mid = start;
for (let i = start + 1; i < end; i++)
if (arr[i] < pivot)
mid++;
swap(arr, i, mid);
swap(arr, mid, start);
return mid;
;
const findMissing = arr =>
let candidate = 1;
let start = 0;
let end = arr.length;
for (;;)
if (start === end)
return candidate;
const pivotIndex = partition(arr, start, end);
const pivot = arr[pivotIndex];
if (pivotIndex + 1 < pivot)
end = pivotIndex;
else
//assert(pivotIndex + 1 === pivot);
candidate = pivot + 1;
start = pivotIndex + 1;
;
const createTestCase = (size, max) =>
if (max < size)
throw new Error('size must be < max');
const arr = Array.from(length: max, (_, i) => i + 1);
const expectedIndex = Math.floor(Math.random() * size);
arr.splice(expectedIndex, 1 + Math.floor(Math.random() * (max - size - 1)));
for (let i = 0; i < size; i++)
let j = i + Math.floor(Math.random() * (size - i));
swap(arr, i, j);
return
input: arr.slice(0, size),
expected: expectedIndex + 1,
;
;
for (let i = 0; i < 5; i++)
const test = createTestCase(1000, 1024);
console.log(findMissing(test.input), test.expected);
'use strict';
const swap = (arr, i, j) =>
[arr[i], arr[j]] = [arr[j], arr[i]];
;
// dummy pivot selection, because this part isn’t important
const selectPivot = (arr, start, end) =>
start + Math.floor(Math.random() * (end - start));
const partition = (arr, start, end) =>
let mid = selectPivot(arr, start, end);
const pivot = arr[mid];
swap(arr, mid, start);
mid = start;
for (let i = start + 1; i < end; i++)
if (arr[i] < pivot)
mid++;
swap(arr, i, mid);
swap(arr, mid, start);
return mid;
;
const findMissing = arr =>
let candidate = 1;
let start = 0;
let end = arr.length;
for (;;)
if (start === end)
return candidate;
const pivotIndex = partition(arr, start, end);
const pivot = arr[pivotIndex];
if (pivotIndex + 1 < pivot)
end = pivotIndex;
else
//assert(pivotIndex + 1 === pivot);
candidate = pivot + 1;
start = pivotIndex + 1;
;
const createTestCase = (size, max) =>
if (max < size)
throw new Error('size must be < max');
const arr = Array.from(length: max, (_, i) => i + 1);
const expectedIndex = Math.floor(Math.random() * size);
arr.splice(expectedIndex, 1 + Math.floor(Math.random() * (max - size - 1)));
for (let i = 0; i < size; i++)
let j = i + Math.floor(Math.random() * (size - i));
swap(arr, i, j);
return
input: arr.slice(0, size),
expected: expectedIndex + 1,
;
;
for (let i = 0; i < 5; i++)
const test = createTestCase(1000, 1024);
console.log(findMissing(test.input), test.expected);
edited Jun 10 at 21:41
community wiki
3 revs
Ry-
Or - on an input of length n you know the output is at most n+1, so pivot at n/2 etc. and do a binary search for the output value. Then T(n) = O(n) + T(n/2) so T(n) = O(n).
– Daniel Schepler
Jun 10 at 21:05
@DanielSchepler: I’m not sure what you mean by a binary search compared to what this is already, but n/2 is a better choice of pivot, thanks.
– Ry-♦
Jun 10 at 21:09
You were mentioning median-of-median partition selection. My idea was to partition based on possible output values not partition the list into rough halves "spatially".
– Daniel Schepler
Jun 10 at 21:10
add a comment |
Or - on an input of length n you know the output is at most n+1, so pivot at n/2 etc. and do a binary search for the output value. Then T(n) = O(n) + T(n/2) so T(n) = O(n).
– Daniel Schepler
Jun 10 at 21:05
@DanielSchepler: I’m not sure what you mean by a binary search compared to what this is already, but n/2 is a better choice of pivot, thanks.
– Ry-♦
Jun 10 at 21:09
You were mentioning median-of-median partition selection. My idea was to partition based on possible output values not partition the list into rough halves "spatially".
– Daniel Schepler
Jun 10 at 21:10
Or - on an input of length n you know the output is at most n+1, so pivot at n/2 etc. and do a binary search for the output value. Then T(n) = O(n) + T(n/2) so T(n) = O(n).
– Daniel Schepler
Jun 10 at 21:05
Or - on an input of length n you know the output is at most n+1, so pivot at n/2 etc. and do a binary search for the output value. Then T(n) = O(n) + T(n/2) so T(n) = O(n).
– Daniel Schepler
Jun 10 at 21:05
@DanielSchepler: I’m not sure what you mean by a binary search compared to what this is already, but n/2 is a better choice of pivot, thanks.
– Ry-♦
Jun 10 at 21:09
@DanielSchepler: I’m not sure what you mean by a binary search compared to what this is already, but n/2 is a better choice of pivot, thanks.
– Ry-♦
Jun 10 at 21:09
You were mentioning median-of-median partition selection. My idea was to partition based on possible output values not partition the list into rough halves "spatially".
– Daniel Schepler
Jun 10 at 21:10
You were mentioning median-of-median partition selection. My idea was to partition based on possible output values not partition the list into rough halves "spatially".
– Daniel Schepler
Jun 10 at 21:10
add a comment |
The correct method I almost got on my own, but I had to search for it, and I found it here: https://www.geeksforgeeks.org/find-the-smallest-positive-number-missing-from-an-unsorted-array/
Note: This method is destructive to the original data
Nothing in the original question said you could not be destructive.
I will explain what you need to do now.
The basic "aha" here is that the fist missing number must come within the first N positive numbers, where N is the length of the array.
Once you understand this and realize you can use the values in the array itself as markers, you just have one problem you need to address: Does the array have numbers less than 1 in it? If so we need to deal with them.
Dealing with 0s or negative numbers can be done in O(n) time. Get two integers, one for our current value, and one for the end of the array. As we scan through, if we find a 0 or negative number, we perform a swap using a third integer, with the final value in the array. Then we decrement our end of array pointer. We continue until our current pointer is past the end of the array pointer.
Code example:
while (list[end] < 1)
end--;
while (cur< end)
if (n < 1)
swap(list[cur], list[end]);
while (list[end] < 1)
end--;
Now we have the end of array, and a truncated array. From here we need to see how we can use the array itself. Since all numbers that we care about are positive, and we have a pointer to the position of how many of them there are, we can simply multiply one by -1 to mark that place as present if there was a number in the array there.
e.g. [5, 3, 2, 7, 1] when we read 3, we change it to [5, 3, -2, 7, 1]
Code example:
for (cur = 0; cur <= end; begin++)
if (!(abs(list[cur]) > end))
list[abs(list[cur]) - 1] *= -1;
Now, note: You need to read the absolute value of the integer in the position, because it might be changed to be negative. Also note, if an integer is greater than your end of list pointer, do not change anything as that integer will not matter.
Finally, once you have read all the positive values, iterate through them to find the first one that is currently positive. This place represents your first missing number.
Step 1: Segregate 0 and negative numbers from your list to the right. O(n)
Step 2: Using the end of list pointer iterate through the entire list marking
relevant positions negative. O(n-k)
Step 3: Scan the numbers for the position of the first non-negative number. O(n-k)
Space Complexity: The original list is not counted, I used 3 integers beyond that. So
it is O(1)
One thing I should mention is the list [5, 4, 2, 1, 3] would end up [-5, -4, -2, -1, -3] so in this case, you would choose the first number after the end position of the list, or 6 as your result.
Code example for step 3:
for (cur = 0; cur < end; cur++)
if (list[cur] > 0)
break;
print(cur);
add a comment |
The correct method I almost got on my own, but I had to search for it, and I found it here: https://www.geeksforgeeks.org/find-the-smallest-positive-number-missing-from-an-unsorted-array/
Note: This method is destructive to the original data
Nothing in the original question said you could not be destructive.
I will explain what you need to do now.
The basic "aha" here is that the fist missing number must come within the first N positive numbers, where N is the length of the array.
Once you understand this and realize you can use the values in the array itself as markers, you just have one problem you need to address: Does the array have numbers less than 1 in it? If so we need to deal with them.
Dealing with 0s or negative numbers can be done in O(n) time. Get two integers, one for our current value, and one for the end of the array. As we scan through, if we find a 0 or negative number, we perform a swap using a third integer, with the final value in the array. Then we decrement our end of array pointer. We continue until our current pointer is past the end of the array pointer.
Code example:
while (list[end] < 1)
end--;
while (cur< end)
if (n < 1)
swap(list[cur], list[end]);
while (list[end] < 1)
end--;
Now we have the end of array, and a truncated array. From here we need to see how we can use the array itself. Since all numbers that we care about are positive, and we have a pointer to the position of how many of them there are, we can simply multiply one by -1 to mark that place as present if there was a number in the array there.
e.g. [5, 3, 2, 7, 1] when we read 3, we change it to [5, 3, -2, 7, 1]
Code example:
for (cur = 0; cur <= end; begin++)
if (!(abs(list[cur]) > end))
list[abs(list[cur]) - 1] *= -1;
Now, note: You need to read the absolute value of the integer in the position, because it might be changed to be negative. Also note, if an integer is greater than your end of list pointer, do not change anything as that integer will not matter.
Finally, once you have read all the positive values, iterate through them to find the first one that is currently positive. This place represents your first missing number.
Step 1: Segregate 0 and negative numbers from your list to the right. O(n)
Step 2: Using the end of list pointer iterate through the entire list marking
relevant positions negative. O(n-k)
Step 3: Scan the numbers for the position of the first non-negative number. O(n-k)
Space Complexity: The original list is not counted, I used 3 integers beyond that. So
it is O(1)
One thing I should mention is the list [5, 4, 2, 1, 3] would end up [-5, -4, -2, -1, -3] so in this case, you would choose the first number after the end position of the list, or 6 as your result.
Code example for step 3:
for (cur = 0; cur < end; cur++)
if (list[cur] > 0)
break;
print(cur);
add a comment |
The correct method I almost got on my own, but I had to search for it, and I found it here: https://www.geeksforgeeks.org/find-the-smallest-positive-number-missing-from-an-unsorted-array/
Note: This method is destructive to the original data
Nothing in the original question said you could not be destructive.
I will explain what you need to do now.
The basic "aha" here is that the fist missing number must come within the first N positive numbers, where N is the length of the array.
Once you understand this and realize you can use the values in the array itself as markers, you just have one problem you need to address: Does the array have numbers less than 1 in it? If so we need to deal with them.
Dealing with 0s or negative numbers can be done in O(n) time. Get two integers, one for our current value, and one for the end of the array. As we scan through, if we find a 0 or negative number, we perform a swap using a third integer, with the final value in the array. Then we decrement our end of array pointer. We continue until our current pointer is past the end of the array pointer.
Code example:
while (list[end] < 1)
end--;
while (cur< end)
if (n < 1)
swap(list[cur], list[end]);
while (list[end] < 1)
end--;
Now we have the end of array, and a truncated array. From here we need to see how we can use the array itself. Since all numbers that we care about are positive, and we have a pointer to the position of how many of them there are, we can simply multiply one by -1 to mark that place as present if there was a number in the array there.
e.g. [5, 3, 2, 7, 1] when we read 3, we change it to [5, 3, -2, 7, 1]
Code example:
for (cur = 0; cur <= end; begin++)
if (!(abs(list[cur]) > end))
list[abs(list[cur]) - 1] *= -1;
Now, note: You need to read the absolute value of the integer in the position, because it might be changed to be negative. Also note, if an integer is greater than your end of list pointer, do not change anything as that integer will not matter.
Finally, once you have read all the positive values, iterate through them to find the first one that is currently positive. This place represents your first missing number.
Step 1: Segregate 0 and negative numbers from your list to the right. O(n)
Step 2: Using the end of list pointer iterate through the entire list marking
relevant positions negative. O(n-k)
Step 3: Scan the numbers for the position of the first non-negative number. O(n-k)
Space Complexity: The original list is not counted, I used 3 integers beyond that. So
it is O(1)
One thing I should mention is the list [5, 4, 2, 1, 3] would end up [-5, -4, -2, -1, -3] so in this case, you would choose the first number after the end position of the list, or 6 as your result.
Code example for step 3:
for (cur = 0; cur < end; cur++)
if (list[cur] > 0)
break;
print(cur);
The correct method I almost got on my own, but I had to search for it, and I found it here: https://www.geeksforgeeks.org/find-the-smallest-positive-number-missing-from-an-unsorted-array/
Note: This method is destructive to the original data
Nothing in the original question said you could not be destructive.
I will explain what you need to do now.
The basic "aha" here is that the fist missing number must come within the first N positive numbers, where N is the length of the array.
Once you understand this and realize you can use the values in the array itself as markers, you just have one problem you need to address: Does the array have numbers less than 1 in it? If so we need to deal with them.
Dealing with 0s or negative numbers can be done in O(n) time. Get two integers, one for our current value, and one for the end of the array. As we scan through, if we find a 0 or negative number, we perform a swap using a third integer, with the final value in the array. Then we decrement our end of array pointer. We continue until our current pointer is past the end of the array pointer.
Code example:
while (list[end] < 1)
end--;
while (cur< end)
if (n < 1)
swap(list[cur], list[end]);
while (list[end] < 1)
end--;
Now we have the end of array, and a truncated array. From here we need to see how we can use the array itself. Since all numbers that we care about are positive, and we have a pointer to the position of how many of them there are, we can simply multiply one by -1 to mark that place as present if there was a number in the array there.
e.g. [5, 3, 2, 7, 1] when we read 3, we change it to [5, 3, -2, 7, 1]
Code example:
for (cur = 0; cur <= end; begin++)
if (!(abs(list[cur]) > end))
list[abs(list[cur]) - 1] *= -1;
Now, note: You need to read the absolute value of the integer in the position, because it might be changed to be negative. Also note, if an integer is greater than your end of list pointer, do not change anything as that integer will not matter.
Finally, once you have read all the positive values, iterate through them to find the first one that is currently positive. This place represents your first missing number.
Step 1: Segregate 0 and negative numbers from your list to the right. O(n)
Step 2: Using the end of list pointer iterate through the entire list marking
relevant positions negative. O(n-k)
Step 3: Scan the numbers for the position of the first non-negative number. O(n-k)
Space Complexity: The original list is not counted, I used 3 integers beyond that. So
it is O(1)
One thing I should mention is the list [5, 4, 2, 1, 3] would end up [-5, -4, -2, -1, -3] so in this case, you would choose the first number after the end position of the list, or 6 as your result.
Code example for step 3:
for (cur = 0; cur < end; cur++)
if (list[cur] > 0)
break;
print(cur);
edited Jun 10 at 22:51
answered Jun 10 at 22:31
Chthonic OneChthonic One
2327
2327
add a comment |
add a comment |
use this algorithm:
A is [5, 3, 2, 7]
1- Define B With Length = A.Length; (O(1))
2- initialize B Cells With 1; (O(n))
3- For Each Item In A:
if (B.Length <= item) then B[Item] = -1 (O(n))
4- The answer is smallest index in B such that B[index] != -1 (O(n))
what's wrong with this solution?!
– Hamed
Jun 11 at 7:52
add a comment |
use this algorithm:
A is [5, 3, 2, 7]
1- Define B With Length = A.Length; (O(1))
2- initialize B Cells With 1; (O(n))
3- For Each Item In A:
if (B.Length <= item) then B[Item] = -1 (O(n))
4- The answer is smallest index in B such that B[index] != -1 (O(n))
what's wrong with this solution?!
– Hamed
Jun 11 at 7:52
add a comment |
use this algorithm:
A is [5, 3, 2, 7]
1- Define B With Length = A.Length; (O(1))
2- initialize B Cells With 1; (O(n))
3- For Each Item In A:
if (B.Length <= item) then B[Item] = -1 (O(n))
4- The answer is smallest index in B such that B[index] != -1 (O(n))
use this algorithm:
A is [5, 3, 2, 7]
1- Define B With Length = A.Length; (O(1))
2- initialize B Cells With 1; (O(n))
3- For Each Item In A:
if (B.Length <= item) then B[Item] = -1 (O(n))
4- The answer is smallest index in B such that B[index] != -1 (O(n))
edited Jun 11 at 7:48
answered Jun 10 at 13:24
HamedHamed
53114
53114
what's wrong with this solution?!
– Hamed
Jun 11 at 7:52
add a comment |
what's wrong with this solution?!
– Hamed
Jun 11 at 7:52
what's wrong with this solution?!
– Hamed
Jun 11 at 7:52
what's wrong with this solution?!
– Hamed
Jun 11 at 7:52
add a comment |
1
No, but finding that max value should be in O(n) and need constant space complexity
– maranic
Jun 10 at 12:43
1
@mnm We need to "find the smallest possible number to insert into it so that every integer is still unique". For
[5,3,2,7], the smallest possible number is 1, but for the second array,1,2,3are all present, so the next possible smalles number is 4.– maranic
Jun 10 at 13:06
1
@SurakofVulcan The only rule is that the values in the array should remain positive integers.
– maranic
Jun 10 at 13:11
1
From the question description: "Assigning values in the array to other integers is allowed." This is O(n) space, not constant.
– גלעד ברקן
Jun 10 at 13:16
2
@גלעדברקן: no. The space of the input data structure doesn't count.
– Yves Daoust
Jun 10 at 13:38