-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgrokking_cyclic_sort.py
335 lines (234 loc) · 9.27 KB
/
grokking_cyclic_sort.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# GROKKING - CYCLIC SORT
# CYCLIC SORT
# Given an array containing n objects. Each object, when created, was assigned a unique number
# from the range 1 to n based on their creation sequence. Write a function to sort the objects
# in-place on their creation sequence number.
from re import L
def cyclic_sort(nums):
i = 0
# Cycle through the entire list of numbers
while i < len(nums):
j = nums[i] - 1
# If the values are different...
if nums[i] != nums[j]:
# ...Swap locations in the array...
nums[i], nums[j] = nums[j], nums[i]
# ...until the array indices are the same, then move to the next i in the cycle
else:
i += 1
return nums
def main():
print(cyclic_sort([3, 1, 5, 4, 2]))
print(cyclic_sort([2, 6, 4, 3, 1, 5]))
print(cyclic_sort([1, 5, 6, 4, 3, 2]))
main()
# Time Complexity - O(n)
# Space Complexity - O(1)
################################################################################################
# FIND THE MISSING NUMBER
# Given an array containing n distinct numbers taken from the range 0 to n. Since the array
# has only n numbers out of the total "n+1" numbers, find the missing number
def find_missing_number(nums):
i = 0
n = len(nums)
while i < n:
j = nums[i]
# if the value is less than the length of array and not equal...
if nums[i] < n and nums[i] != nums[j]:
# ...swap locations in the array
nums[i], nums[j] = nums[j], nums[i]
# otherwise, go to the next step in the cycle
else:
i += 1
# Once the list has been sorted, check that all values match their index
# If a number is missing from it's index, return the value
for i in range(0, n):
if nums[i] != i:
return i
# If no values are missing, return the lenngth of the array
return n
def main():
print(find_missing_number([4, 0, 3, 1]))
print(find_missing_number([8, 3, 5, 2, 4, 6, 0, 1]))
main()
# Time Complexity - O(n)
# Space Complexity - O(1)
################################################################################################
# FIND ALL MISSING NUMBERS
# Given an unsorted array containing numbers taken from the range 1 to 'n'. The array can have
# duplicates, which means some numbers will be missing. Find all those missing numbers.
def find_missing_numbers(nums):
i = 0
while i < len(nums):
j = nums[i] - 1
# If the values are different...
if nums[i] != nums[j]:
# ...Swap locations in the array...
nums[i], nums[j] = nums[j], nums[i]
# ...until the array indices are the same, then move to the next i in the cycle
else:
i += 1
missing_numbers = []
# Once te list is sorted, cycle through and add all missing values to an array
for i in range(len(nums)):
if nums[i] != i + 1:
missing_numbers.append(i + 1)
return missing_numbers
def main():
print(find_missing_numbers([2, 3, 1, 8, 2, 3, 5, 1]))
print(find_missing_numbers([2, 4, 1, 2]))
print(find_missing_numbers([2, 3, 2, 1]))
main()
# Time Complexity - O(n)
# Space Complexity - O(1)
################################################################################################
# FIND THE DUPLICATE NUMBER
# Given an unsorted array containing 'n+1' numbers taken from the range 1 to 'n'. The array
# has only one duplicate but it can be repeated multiple time. Find that duplicate number without
# using any extra space - modify the input array.
def find_duplicate(nums):
i = 0
while i < len(nums):
# If the value is not equal to its corresponding index
if nums[i] != i + 1:
j = nums[i] - 1
# If the values are different...
if nums[i] != nums[j]:
# ...Swap locations in the array...
nums[i], nums[j] = nums[j], nums[i]
# ...otherwise, we've found the duplicate
else:
return nums[i]
# When the value is equal to the index, move to the next step in the cycle
else:
i += 1
# If there are no duplicate values, return -1
return -1
def main():
print(find_duplicate([1, 4, 4, 3, 2]))
print(find_duplicate([2, 1, 3, 3, 5, 4]))
print(find_duplicate([2, 4, 1, 4, 4]))
main()
# Time Complexity - O(n)
# Space Complexity - O(1)
################################################################################################
# FIND ALL DUPLICATE NUMBERS
# Given an unsorted array containing 'n' numbers taken from the range 1 to n. The array has
# some numbers appearing twice, find all these duplicate numbers using constant space.
def find_all_duplicates(nums):
i = 0
while i < len(nums):
j = nums[i] - 1
# If the values are different...
if nums[i] != nums[j]:
# ...Swap locations in the array...
nums[i], nums[j] = nums[j], nums[i]
# ...until the array indices are the same, then move to the next i in the cycle
else:
i += 1
duplicate_numbers = []
# Once te list is sorted, cycle through and add all duplicate values to an array
for i in range(len(nums)):
if nums[i] != i + 1:
duplicate_numbers.append(nums[i])
return duplicate_numbers
def main():
print(find_all_duplicates([3, 4, 4, 5, 5]))
print(find_all_duplicates([5, 4, 7, 2, 3, 5, 3]))
main()
# Time Complexity - O(n)
# Space Complexity - O(1)
################################################################################################
# CHALLENGE 1: FIND THE CORRUPT PAIR
# Given an unsorted array containing 'n' numbers taken from the range 1 to 'n'. The array
# originally contained all the numbers from 1 to 'n', but due to a data error, one of the
# numbers got duplicated which also resulted in one number going missing. Find both these numbers.
def find_corrupt_numbers(nums):
i = 0
while i < len(nums):
j = nums[i] - 1
# If the values are different...
if nums[i] != nums[j]:
# ...Swap locations in the array...
nums[i], nums[j] = nums[j], nums[i]
# ...until the array indices are the same, then move to the next i in the cycle
else:
i += 1
# Once te list is sorted, cycle through and return corrupt values
for i in range(len(nums)):
if nums[i] != i + 1:
return [nums[i], i + 1]
# If there are no corrupt values, return [-1, -1]
return [-1, -1]
def main():
print(find_corrupt_numbers([3, 1, 2, 5, 2]))
print(find_corrupt_numbers([3, 1, 2, 3, 6, 4]))
main()
# Time Complexity - O(n)
# Space Complexity - O(1)
################################################################################################
# CHALLENGE 2: FIND THE SMALLEST MISSING POSITIVE NUMBER
# Given an unsorted array containing numbers, find the smallest missing positive number in it
def find_first_smallest_missing_positive(nums):
i = 0
n = len(nums)
while i < n:
j = nums[i] - 1
if nums[i] > 0 and nums[i] <= n and nums[i] != nums[j]:
# Swap locations in the array...
nums[i], nums[j] = nums[j], nums[i]
# ...then move to the next i in the cycle
else:
i += 1
# Once the list is sorted, iterate through the array and return the first index
# that does not have the correct number
for i in range(n):
if nums[i] != i + 1:
return i + 1
# Otherwise, return the length of the array plus 1
return len(nums) + 1
def main():
print(find_first_smallest_missing_positive([-3, 1, 5, 4, 2]))
print(find_first_smallest_missing_positive([3, -2, 0, 1, 2]))
print(find_first_smallest_missing_positive([3, 2, 5, 1]))
main()
# Time Complexity - O(n)
# Space Complexity - O(1)
################################################################################################
# CHALLENGE 3: FIND THE FIRST K MISSING POSITIVE NUMBERS
# Given an unsorted array containing numbers and a number 'k', find the first 'k' missing positive
# numbers in the array.
def find_first_k_missing_positive(nums, k):
n = len(nums)
i = 0
while i < len(nums):
j = nums[i] - 1
if nums[i] > 0 and nums[i] <= n and nums[i] != nums[j]:
# swap locations in the array
nums[i], nums[j] = nums[j], nums[i]
# move to the next step in the cycle
else:
i += 1
missing_numbers = []
extra_numbers = set()
for i in range(n):
if len(missing_numbers) < k:
if nums[i] != i + 1:
missing_numbers.append(i+1)
extra_numbers.add(nums[i])
# add the remaining missing numbers
i = 1
while len(missing_numbers) < k:
candidate_number = i + n
# ignore if the array contains the candidate number
if candidate_number not in extra_numbers:
missing_numbers.append(candidate_number)
i += 1
return missing_numbers
def main():
print(find_first_k_missing_positive([3, -1, 4, 5, 5], 3))
print(find_first_k_missing_positive([2, 3, 4], 3))
print(find_first_k_missing_positive([-2, -3, 4], 2))
main()
# Time Complexity - O(n) and O(k) respectively
# Space Complexity - O(k)