Daily Coding Problem: Problem #4
Problem
This problem was asked by Stripe.
Given an array of integers, find the first missing positive integer in linear time and constant space. In other words, find the lowest positive integer that does not exist in the array. The array can contain duplicates and negative numbers as well.
For example, the input [3, 4, -1, 1] should give 2. The input [1, 2, 0] should give 3.
You can modify the input array in-place.
Solution
To solve this, you should think what’s common between array indexes and a positive integer: it’s the same thing.
So we put each positive integer of an array at its place (i+1 since we count from 1) and then iterate again to find first missing.
If we don’t, return length plus one (=next).
Code
func solution(aa []int) int {
if len(aa) == 0 {
return 1
}
for _, a := range aa { // try to place all numbers at same index (from 1)
if a < 0 { // we don't care, it's negative
continue
}
if a >= len(aa) { // we don't care, result always < len(aa)
continue
}
aa[a-1] = a
}
for i := range aa { // find first missing
if aa[i] != i+1 {
return i + 1
}
}
return len(aa) + 1 // all there
}
Benchmarks
goos: darwin
goarch: amd64
pkg: github.com/ngalayko/dcp/problems/2018-07-05
Benchmark/0-4 1000000000 2.18 ns/op 0 B/op 0 allocs/op
Benchmark/100-4 20000000 65.0 ns/op 0 B/op 0 allocs/op
Benchmark/200-4 10000000 122 ns/op 0 B/op 0 allocs/op
Benchmark/300-4 10000000 178 ns/op 0 B/op 0 allocs/op
Benchmark/400-4 10000000 238 ns/op 0 B/op 0 allocs/op
Benchmark/500-4 5000000 295 ns/op 0 B/op 0 allocs/op
Benchmark/600-4 5000000 354 ns/op 0 B/op 0 allocs/op
Benchmark/700-4 3000000 410 ns/op 0 B/op 0 allocs/op
Benchmark/800-4 3000000 466 ns/op 0 B/op 0 allocs/op
Benchmark/900-4 3000000 528 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/ngalayko/dcp/problems/2018-07-05 19.293s
UPDATE
As it was mentioned in the comments, the first solution fails in case of [3,2,4,-1,1]
It happens because when we place an integer to its position in the array, we also delete integer that used to be in that place.
To avoid this, instead of just placing the integer, I swap it with the current one and process current index one more time.
func solution(aa []int) int {
if len(aa) == 0 {
return 1
}
for i := 0; i < len(aa); i++ {
a := aa[i]
if a < 0 { // we don't care, it's negative
continue
}
if a >= len(aa) { // we don't care, result always < len(aa)
continue
}
if a == aa[a-1] { // if integer on it's place, skip
continue
}
// put each integer on it's place
// decrease i, because aa[i] is a new integer now and we need to
// process it one more time
aa[i], aa[a-1] = aa[a-1], aa[i]
i--
}
for i := range aa { // find first missing
if aa[i] != i+1 {
return i + 1
}
}
return len(aa) + 1 // all there
}