The standard binary search template. Foundation for all logarithmic search problems.
lo, hi = 0, len(a) - 1
while lo <= hi:
mid = lo + (hi - lo) // 2
if a[mid] == target: return mid
elif a[mid] < target: lo = mid + 1
else: hi = mid - 1
Safe midpoint calculation prevents integer overflow. Critical for correct binary search.
mid = lo + (hi - lo) // 2
Left boundary search finds the first occurrence. Key for range queries and count problems.
lo, hi = 0, len(a)
while lo < hi:
mid = lo + (hi - lo) // 2
if a[mid] < target: lo = mid + 1
else: hi = mid
return lo
Right boundary search finds the insertion point after equals. Paired with bisect_left for range counting.
lo, hi = 0, len(a)
while lo < hi:
mid = lo + (hi - lo) // 2
if a[mid] <= target: lo = mid + 1
else: hi = mid
return lo
bisect_left gives the insertion index directly. Foundation for sorted-container operations.
import bisect
pos = bisect.bisect_left(a, target)
# pos is the insert index
heappush maintains the min-heap invariant. Used in merge-k-lists and streaming median.
import heapq
heapq.heappush(h, val)
heappop extracts the minimum. Pair with heappush for priority queue operations.
import heapq
heapq.heappop(h)
heapify converts a list to a heap in O(n). Faster than n individual pushes.
import heapq
heapq.heapify(a)
nlargest uses a min-heap of size k internally. O(n log k) for top-k problems.
import heapq
top_k = heapq.nlargest(k, a)
Priority queues power Dijkstra's algorithm and task scheduling problems.
import heapq
heapq.heappush(h, (priority, item))
_, item = heapq.heappop(h)
Binary search for the largest integer whose square <= x. Return hi (not lo) because lo overshoots by 1.
lo, hi = 0, x
while lo <= hi:
mid = (lo + hi) // 2
if mid * mid <= x:
lo = mid + 1
else:
hi = mid - 1
return hi
Move toward the higher neighbor — a peak must exist on that side. Uses lo < hi (not <=) and hi = mid (not mid-1).
lo, hi = 0, len(a) - 1
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < a[mid + 1]:
lo = mid + 1
else:
hi = mid
return lo