Skip to content

Commit 078bcf6

Browse files
committed
LC 704. Binary Search (Python reformat)
1 parent dbf60ac commit 078bcf6

File tree

1 file changed

+67
-56
lines changed

1 file changed

+67
-56
lines changed

leetcode/binary-search.py

+67-56
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,56 @@
1+
# 704. Binary Search
2+
# 🟢 Easy
3+
#
14
# https://leetcode.com/problems/binary-search/
5+
#
6+
# Tags: Array - Binary Search
27

38

49
import timeit
510
from typing import List
611

7-
# The loop solution is the most efficient on LeetCode.
8-
# Using the built-in method index is the most efficient locally.
12+
# The iterative solution is the most efficient on LeetCode, using the
13+
# built-in method index is the most efficient locally.
914
#
10-
# Index 0.01493 seconds
11-
# Loop 0.02365 seconds
15+
# BuiltIn 0.01493 seconds
16+
# Iterative 0.02365 seconds
1217
# Recursive 0.04586 seconds
1318

1419

15-
# Use a loop to do binary search.
20+
# Use a left and right pointer, at each iteration compute the mid-point
21+
# between them, when the value at that mid index is greater than the
22+
# target, we know that the target will be to the left if it found in the
23+
# array, when the value is lesser, it will be found to the right.
24+
#
25+
# Time complexity: O(log(n)) - Each iteration discards half of the
26+
# search space.
27+
# Space complexity: O(1) - We use constant space.
1628
#
17-
# Runtime: 249 ms, faster than 94.42% of Python3 online submissions for Binary Search.
18-
# Memory Usage: 15.4 MB, less than 71.46 % of Python3 online submissions for Binary Search.
19-
class Loop:
29+
# Runtime 235 ms Beats 94.42%
30+
# Memory 15.4 MB Beats 96.81%
31+
class Iterative:
2032
def search(self, nums: List[int], target: int) -> int:
21-
start = 0
22-
end = len(nums) - 1
23-
while start <= end:
24-
if nums[start] == target:
25-
return start
26-
if nums[end] == target:
27-
return end
28-
mid = (start + end) // 2
29-
if nums[mid] == target:
30-
return mid
31-
if nums[mid] > target:
32-
end = mid-1
33+
l, r = 0, len(nums) - 1
34+
while l < r:
35+
mid = (l + r) // 2
3336
if nums[mid] < target:
34-
start = mid+1
35-
return -1
37+
l = mid + 1
38+
else:
39+
r = mid
40+
return l if nums[l] == target else -1
3641

3742

38-
# Use the built-in index method
43+
# Use the built-in index method wrapped in a try-catch block, if the
44+
# method does not find the target, it will throw an exception, catch it
45+
# and return -1.
3946
#
47+
# Time complexity: O(log(n)) - Each iteration discards half of the
48+
# search space.
49+
# Space complexity: O(1) - We use constant space.
4050
#
41-
42-
# Use the built-in index method.
43-
#
44-
# Runtime: 343 ms, faster than 49.28% of Python3 online submissions for Binary Search.
45-
# Memory Usage: 15.5 MB, less than 71.46 % of Python3 online submissions for Binary Search.
46-
47-
48-
class Index:
51+
# Runtime: 343 ms Beats 49.28%
52+
# Memory 15.5 MB Beats 71.46%
53+
class BuiltIn:
4954
def search(self, nums: List[int], target: int) -> int:
5055
try:
5156
return nums.index(target)
@@ -55,52 +60,58 @@ def search(self, nums: List[int], target: int) -> int:
5560

5661
# Use a recursive call to implement binary search.
5762
#
58-
# Runtime: 355 ms, faster than 45.00% of Python3 online submissions for Binary Search.
59-
# Memory Usage: 22.9 MB, less than 21.93 % of Python3 online submissions for Binary Search.
63+
# Time complexity: O(log(n)) - Each iteration discards half of the
64+
# search space.
65+
# Space complexity: O(log(n)) - The height of the call stack will grow
66+
# by one with each call to the recursive method.
67+
#
68+
# Runtime 355 ms Beats 45.00%
69+
# Memory 22.9 MB Beats 21.93%
6070
class Recursive:
6171
def search(self, nums: List[int], target: int) -> int:
62-
def s(start: int, end: int) -> int:
63-
if start > end:
72+
def s(lo: int, hi: int) -> int:
73+
if lo > hi:
6474
return -1
65-
if nums[start] == target:
66-
return start
67-
if nums[end] == target:
68-
return end
69-
mid = (start + end) // 2
75+
mid = (lo + hi) // 2
7076
if nums[mid] == target:
7177
return mid
7278
if nums[mid] < target:
73-
return s(mid+1, end)
79+
return s(mid + 1, hi)
7480
if nums[mid] > target:
75-
return s(start, mid-1)
81+
return s(lo, mid - 1)
7682
return -1
77-
return s(0, len(nums)-1)
83+
84+
return s(0, len(nums) - 1)
7885

7986

8087
def test():
81-
executor = [
82-
{'executor': Index, 'title': 'Index', },
83-
{'executor': Loop, 'title': 'Loop', },
84-
{'executor': Recursive, 'title': 'Recursive', },
88+
executors = [
89+
Iterative,
90+
BuiltIn,
91+
Recursive,
8592
]
8693
tests = [
87-
[[], 2, -1],
8894
[[5], 5, 0],
8995
[[-4, -2, 0, 1], 2, -1],
9096
[[-1, 0, 3, 5, 9, 12], 9, 4],
9197
[[-1, 0, 3, 5, 9, 12], 2, -1],
9298
]
93-
for e in executor:
99+
for executor in executors:
94100
start = timeit.default_timer()
95-
for _ in range(int(float('1e4'))):
96-
for t in tests:
97-
sol = e['executor']()
98-
result = sol.search([*t[0]], t[1])
99-
expected = t[2]
100-
assert result == expected, f'{result} != {expected} for {t[0]}:{t[1]} using {e["title"]} solution'
101+
for _ in range(1):
102+
for col, t in enumerate(tests):
103+
sol = executor()
104+
result = sol.search(t[0], t[1])
105+
exp = t[2]
106+
assert result == exp, (
107+
f"\033[93m» {result} <> {exp}\033[91m for"
108+
+ f" test {col} using \033[1m{executor.__name__}"
109+
)
101110
stop = timeit.default_timer()
102111
used = str(round(stop - start, 5))
103-
print("{0:20}{1:10}{2:10}".format(e['title'], used, "seconds"))
112+
cols = "{0:20}{1:10}{2:10}"
113+
res = cols.format(executor.__name__, used, "seconds")
114+
print(f"\033[92m» {res}\033[0m")
104115

105116

106117
test()

0 commit comments

Comments
 (0)