Released · improving
Algorithm
Searching finds a value or position in data: linear search, binary search, lower_bound and upper_bound, binary search on the answer, and hash lookups.
Searching is the task of finding a value, or the position where some condition first holds, inside a collection of data. Linear search checks elements one by one and works on any data, while binary search halves a sorted range at every step and needs only about 20 comparisons for a million elements. For exact-match lookups, a hash table answers in constant time on average.
Searching matters because almost every program looks things up: database indexes, autocomplete, log analysis and routing tables all rely on it. Binary search also goes beyond arrays. Whenever a yes/no condition flips only once over a range, you can binary search the answer itself, which turns many optimization problems in coding interviews into short, reliable code.
Start by writing linear search and a closed-interval binary search yourself, then practice the half-open lower_bound and upper_bound forms until the boundary handling feels natural. Trace small arrays by hand, test your code against Python's bisect module with random inputs, and finally work through optimization problems that call for binary search on the answer and ternary search.
Compares elements one by one in O(n) time. It needs no sorting and is often the fastest option for small collections.
Halves a sorted range at every step and finds values in O(log n) time. An iterative version uses only O(1) extra memory.
Return the first position whose value is at least, or strictly greater than, the target. Their difference counts duplicates, and Python's bisect module provides both.
Parametric search turns 'what is the smallest feasible value?' into a yes/no test and binary searches the range of possible answers.
lower_bound returns the first index whose value is at least x, working on the half-open range [lo, hi). When the middle value is smaller than x it discards the left half; otherwise it discards the right half. contains uses that index to test membership, and the last line confirms the result matches bisect.bisect_left from the standard library.
searching.py
from bisect import bisect_left
def lower_bound(a, x):
"""Return the first index i with a[i] >= x (len(a) if there is none)."""
lo, hi = 0, len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < x:
lo = mid + 1
else:
hi = mid
return lo
def contains(a, x):
i = lower_bound(a, x)
return i < len(a) and a[i] == x
if __name__ == "__main__":
data = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
print(lower_bound(data, 23), contains(data, 23)) # 5 True
print(lower_bound(data, 24), contains(data, 24)) # 6 False
print(lower_bound(data, 24) == bisect_left(data, 24)) # True
python searching.pySix chapters that take you from installation to the core ideas of Searching.
Ask questions, share experience and trade opinions about Searching.
No discussions yet. Start the first one.
0 comments
Sign in · Sign in to leave a comment.
Be the first to comment.