Skip to content

Commit 55a1b7c

Browse files
BrianLusinaBrianLusina
authored andcommitted
feat(puzzles): cyclically shifted array
Using binary search to find the index of the smallest number in a cyclically shifted array
1 parent acafb89 commit 55a1b7c

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Cyclically Shifted Array
2+
3+
Return the index of the smallest number in a cyclically shifted array.
4+
5+
An array is “cyclically shifted” if it is possible to shift its entries cyclically so that it becomes sorted.
6+
7+
The following list is an example of a cyclically shifted array:
8+
9+
A = [4, 5, 6, 7, 1, 2, 3]
10+
11+
Below are all the possible cyclic shifts of an array:
12+
13+
```plain
14+
Array A: [1,2,3,4,5,6,7]
15+
16+
[2,3,4,5,6,7,1]
17+
[5,6,7,1,2,3,4]
18+
[3,4,5,6,7,1,2]
19+
[6,7,1,2,3,4,5]
20+
[4,5,6,7,1,2,3]
21+
[7,1,2,3,4,5,6]
22+
```
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from typing import List
2+
3+
def find_index_of_smallest_number(numbers: List[int]) -> int:
4+
"""
5+
Finds the index of the smallest number in a cyclically shifted array
6+
7+
Args:
8+
numbers (list): cyclically shifted array
9+
Returns:
10+
int: index of the smallest number in a cyclically shifted array
11+
"""
12+
left_pointer = 0
13+
right_pointer = len(numbers) - 1
14+
15+
while left_pointer < right_pointer:
16+
middle = (left_pointer + right_pointer) >> 1
17+
18+
# if the number in the middle is less than or equal to the number on the right, this means that the search space
19+
# should be moved to the left. Eliminating numbers on the right by moving the right pointer to the middle. This
20+
# is because the numbers are increasing, therefore the numbers we are looking for can not be on the right
21+
if numbers[middle] <= numbers[right_pointer]:
22+
right_pointer = middle
23+
elif numbers[middle] > numbers[right_pointer]:
24+
# move the left pointer to the middle + 1 to eliminate the search space on the left if the middle number
25+
# is greater than the number at the right pointer. This is because the numbers are decreasing from the middle
26+
# therefore we can possibly find the number we are searching for in the right search space
27+
left_pointer = middle + 1
28+
29+
return left_pointer
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import unittest
2+
from . import find_index_of_smallest_number
3+
4+
5+
class FindIndexOfSmallestNumberTestCase(unittest.TestCase):
6+
def test_1(self):
7+
"""should return 4 in input of [4, 5, 6, 7, 1, 2, 3]"""
8+
numbers = [4, 5, 6, 7, 1, 2, 3]
9+
expected = 4
10+
actual = find_index_of_smallest_number(numbers)
11+
self.assertEqual(expected, actual)
12+
13+
def test_2(self):
14+
"""should return 2 in input of [6, 7, 1, 2, 3, 4, 5]"""
15+
numbers = [6, 7, 1, 2, 3, 4, 5]
16+
expected = 2
17+
actual = find_index_of_smallest_number(numbers)
18+
self.assertEqual(expected, actual)
19+
20+
def test_3(self):
21+
"""should return 1 in input of [7, 1, 2, 3, 4, 5, 6]"""
22+
numbers = [7, 1, 2, 3, 4, 5, 6]
23+
expected = 1
24+
actual = find_index_of_smallest_number(numbers)
25+
self.assertEqual(expected, actual)
26+
27+
def test_4(self):
28+
"""should return 0 in input of [1, 2, 3, 4, 5, 6, 7]"""
29+
numbers = [1, 2, 3, 4, 5, 6, 7]
30+
expected = 0
31+
actual = find_index_of_smallest_number(numbers)
32+
self.assertEqual(expected, actual)
33+
34+
def test_5(self):
35+
"""should return 5 in input of [3, 4, 5, 6, 7, 1, 2]"""
36+
numbers = [3, 4, 5, 6, 7, 1, 2]
37+
expected = 5
38+
actual = find_index_of_smallest_number(numbers)
39+
self.assertEqual(expected, actual)
40+
41+
def test_6(self):
42+
"""should return 6 in input of [2, 3, 4, 5, 6, 7, 1]"""
43+
numbers = [2, 3, 4, 5, 6, 7, 1]
44+
expected = 6
45+
actual = find_index_of_smallest_number(numbers)
46+
self.assertEqual(expected, actual)
47+
48+
def test_7(self):
49+
"""should return 3 in input of [5, 6, 7, 1, 2, 3, 5]"""
50+
numbers = [5, 6, 7, 1, 2, 3, 5]
51+
expected = 3
52+
actual = find_index_of_smallest_number(numbers)
53+
self.assertEqual(expected, actual)
54+
55+
if __name__ == '__main__':
56+
unittest.main()

puzzles/search/binary_search/integer_square_root/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ def integer_square_root(k: int) -> int:
1515
mid_squared = mid * mid
1616

1717
if mid_squared <= k:
18+
# this discards all the numbers less than mid, i.e. moves the left pointer to be 1 greater than mid
1819
left = mid + 1
1920
else:
21+
# otherwise, we discard all the numbers greater than mid, i.e. move the right pointer to 1 less than mid
2022
right = mid - 1
2123

24+
# this becomes the largest integer whose square is less than the provided integer k
2225
return left - 1

0 commit comments

Comments
 (0)