Searching ā Linear Search, Binary Search & Search Space Elimination
Module 4 ā Searching: Linear Search, Binary Search & Boundary Analysis Structured as Topic ā Plain-English Explanation ā Real Code ā Visual Diagram ā Complexity ā Common Pitfalls.
1. Linear Search vs Binary Search Mechanics
- Linear Search: Examines every element from index 0 to $n-1$. It requires zero preconditions ā works on any array, linked list, or unsorted sequence. In the worst case, it takes $O(n)$ comparisons.
- Binary Search: Operates exclusively on monotonically sorted or partitioned search spaces. By comparing the middle element $mid$ with the target, it instantly eliminates 50% of the entire remaining candidate space. In the worst case, it runs in strictly logarithmic $O(log_2 n)$ time.
// Binary Search with overflow-safe midpoint calculation
int binarySearch(const vector<int>& arr, int target) {
int lo = 0, hi = arr.size() - 1;
while (lo <= hi) {
// Safe against integer overflow (lo + hi can exceed INT_MAX)
int mid = lo + (hi - lo) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
return -1;
}
Figure 4.1 ā Binary search eliminates 50% of the remaining search window at each comparison
2. Lower Bound vs Upper Bound Mechanics
In interviews, you frequently need to find the boundaries of duplicate values:
- Lower Bound: The first index $i$ such that $arr[i] ge target$.
- Upper Bound: The first index $i$ such that $arr[i] > target$.
- Count of occurrences: $ ext{upper_bound} - ext{lower_bound}$.
Figure 4.2 ā Lower bound (≥ target) vs upper bound (> target) pointer positioning
// Lower Bound implementation
int lowerBound(const vector<int>& arr, int target) {
int lo = 0, hi = arr.size();
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] >= target) hi = mid;
else lo = mid + 1;
}
return lo;
}
3. Searching in a Rotated Sorted Array
Even when an array is rotated (e.g., [4, 5, 6, 7, 0, 1, 2]), at least one half (left or right) is always normally sorted!
- Calculate
mid. - Check if left half (
arr[lo] <= arr[mid]) is sorted:- If target lies between
arr[lo]andarr[mid], narrow search to left half (hi = mid - 1). - Otherwise, search right half (
lo = mid + 1).
- If target lies between
- Otherwise, right half must be sorted:
- If target lies between
arr[mid]andarr[hi], narrow search to right half (lo = mid + 1). - Otherwise, search left half (
hi = mid - 1).
- If target lies between
Time Complexity remains strictly $O(log n)$.
Common Pitfall: Writing `int mid = (lo + hi) / 2;` causes integer overflow in languages with fixed 32-bit integers (C++, Java, C#) when `lo + hi > 2,147,483,647`. Always write `int mid = lo + (hi - lo) / 2;`.
Practice Searching MCQs
Master Searching concepts with timed, competitive MCQs with detailed explanations.