-
Notifications
You must be signed in to change notification settings - Fork 0
/
ex-4-1-missinginteger.py
139 lines (106 loc) · 3.58 KB
/
ex-4-1-missinginteger.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""
# Missing Integer
Find the minimal positive integer not occurring in the given sequence.
Write a function:
def solution(A)
that, given a non-empty zero-indexed array A of N integers, returns the minimal positive integer (greater than 0)
that does not occur in A.
For example, given:
A[0] = 1
A[1] = 3
A[2] = 6
A[3] = 4
A[4] = 1
A[5] = 2
the function should return 5.
Assume that:
* N is an integer within the range [1..100,000]
* each element of array A is an integer within the range [-2,147,483,648..2,147,483,647].
Complexity:
* expected worst-case time complexity is O(N)
* expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input
arguments).
Elements of input arrays can be modified.
"""
import unittest
import random
N_RANGE = (1, 100000)
ELEMENT_RANGE = (-2147483648, 2147483647)
def solution(A):
"""
:param A: non-empty list of integers
:return: an integer - the smallest positive integer that is missing
"""
missing = 1
for elem in sorted(A):
if elem == missing:
missing += 1
if elem > missing:
break
return missing
def alternate_solution(A):
"""
A 'Pidgeon Hole' solution:
:param A: non-empty list of integers
:return: an integer - the smallest positive integer that is missing
"""
# dictionary of booleans indicating which ints we've seen
roll = {}
largest = 0
# mark the roll
for element in A:
if element > 0:
roll[element] = True
# track the largest int
if element > largest:
largest = element
# find the first missing element
# NB: using `not in roll.keys()` contributes an O(N) loop which ruins time complexity on the codility platform
counter = 1
while counter <= largest:
if counter in roll:
counter += 1
else:
break
return counter
class TestExercise(unittest.TestCase):
def test_example(self):
self.assertEqual(solution([1, 3, 6, 4, 1, 2]), 5)
def test_extreme_single(self):
self.assertEqual(solution([2]), 1)
self.assertEqual(solution([1]), 2)
self.assertEqual(solution([-1]), 1)
def test_simple(self):
self.assertEqual(solution([2,3,4,6,10,1000]), 1)
self.assertEqual(solution([-1, 0, 1, 2, 3, 4, 5, 6, 10, 1000]), 7)
self.assertEqual(solution([1000, -1, 10, 3, -5, 2, 11, 59, 1]), 4)
def test_extreme_min_max_int(self):
self.assertEqual(1, solution([ELEMENT_RANGE[0], ELEMENT_RANGE[1], -10]))
def test_positive_only(self):
arr = range(1, 101) + range(102, 201)
random.shuffle(arr)
self.assertEqual(solution(arr), 101)
def test_negative_only(self):
arr = range(-100, 0)
random.shuffle(arr)
self.assertEqual(solution(arr), 1)
def test_no_gaps(self):
self.assertEqual(solution([1, 2, 3, 4, 5]), 6)
def test_duplicates(self):
self.assertEqual(solution([1, 1, 1, 3, 3, 3]), 2)
def test_large_2(self):
# create big array of ints
arr = range(1,100000)
random.shuffle(arr)
# remove one
missing_idx = random.randint(1, len(arr))
missing_int = arr[missing_idx]
del arr[missing_idx]
# run it
self.assertEqual(solution(arr), missing_int)
def test_monster_positive(self):
arr = [random.randint(*ELEMENT_RANGE) for _ in xrange(1, N_RANGE[1])]
random.shuffle(arr)
print solution(arr), arr
if __name__ == '__main__':
unittest.main()