Binary Search
I. In-Class Exercises
Programming Exercises
- Binary Search: Find the index of a specific number in a non-duplicate array: L3131
- Binary Search: For an array with possible duplicates, find the smallest index equal to a given number: L3132
- Binary Search: Find the largest index less than or equal to a given number: L3133
II. Knowledge Summary
✨ Core Idea
Binary Search is an efficient search algorithm used to find a specific element in a sorted array. It achieves low time complexity by progressively narrowing the search range, making it one of the most fundamental and important algorithms.
Key characteristics of binary search:
- Prerequisite: Binary search can only be used on sorted arrays or lists
- How it works: By comparing the target value with the middle element, it decides which half of the array to continue searching in, progressively narrowing the range until the target is found or the range is empty
- High efficiency: Compared to linear search, binary search is much faster, especially when dealing with large datasets
- Limitation: The array must be sorted. If the data is unsorted, it needs to be sorted first, which may add extra time overhead
✨ Algorithm Principle
The specific execution steps of binary search are as follows:
- Initialize boundaries: Set two pointers,
leftandright, pointing to the start and end positions of the array respectively. - Calculate the midpoint: Compute the midpoint index
mid, typically using the formulamid = left + (right - left) / 2to avoid potential integer overflow. - Compare the midpoint value:
- If
a[mid]equals the target valuetarget, return the midpoint index - If
a[mid]is less thantarget, updatelefttomid + 1and continue searching in the right half - If
a[mid]is greater thantarget, updaterighttomid - 1and continue searching in the left half
- If
- Loop termination: When
leftexceedsright, the target value was not found.
✨ Algorithm Evaluation
- Time Complexity: O(log n). Each operation halves the search range, so even with millions of data points, only about 20 comparisons are needed to complete the search.
- Space Complexity: O(1). Only constant extra space is used (iterative implementation).
✨ Application Scenarios
Binary search is suitable for the following scenarios:
- Finding a specific value in sorted data
- Solving problems with monotonicity (such as minimization and maximization problems)
- Implementing efficient dynamic data structures (such as operations in balanced binary search trees)
✨ Code Implementation
Here is the standard binary search code implementation that searches for a target value in a sorted array and returns its index:
1#include <iostream>
2#include <vector>
3using namespace std;
4
5int binarySearch(const vector<int>& nums, int target) {
6 int left = 0;
7 int right = nums.size() - 1;
8
9 while (left <= right) {
10 int mid = left + (right - left) / 2;
11
12 if (nums[mid] == target) {
13 return mid; // Target found, return index
14 } else if (nums[mid] < target) {
15 left = mid + 1; // Target is in the right half
16 } else {
17 right = mid - 1; // Target is in the left half
18 }
19 }
20
21 return -1; // Target not found, return -1
22}
23
24int main() {
25 vector<int> nums = {1, 3, 5, 7, 9, 11};
26 int target = 7;
27
28 int result = binarySearch(nums, target);
29 if (result != -1) {
30 cout << "Element found at index " << result << endl;
31 } else {
32 cout << "Element not found" << endl;
33 }
34
35 return 0;
36}✨ Execution Example
Using the sorted array [2, 5, 8, 12, 16, 23, 38, 56, 72, 91] to search for target=23 as an example:
| Round | left | right | mid | nums[mid] | Compare with target | Action |
|---|---|---|---|---|---|---|
| 1 | 0 | 9 | 4 | 16 | 16 < 23 | left = 4+1 = 5 |
| 2 | 5 | 9 | 7 | 56 | 56 > 23 | right = 7-1 = 6 |
| 3 | 5 | 6 | 5 | 23 | 23 == 23 | Found, return 5 |
Only 3 comparisons were needed to find the target, while linear search would require 6.
Now let's look at an example of searching for a non-existent element: searching for target=20 in the same array:
| Round | left | right | mid | nums[mid] | Compare with target | Action |
|---|---|---|---|---|---|---|
| 1 | 0 | 9 | 4 | 16 | 16 < 20 | left = 5 |
| 2 | 5 | 9 | 7 | 56 | 56 > 20 | right = 6 |
| 3 | 5 | 6 | 5 | 23 | 23 > 20 | right = 4 |
| 4 | left=5 > right=4 | - | - | - | Loop ends | Return -1 |
After 4 comparisons, it is determined that the element does not exist.
✨ Detailed Problem-Solving Steps
When encountering binary search problems, pay special attention to the differences between variants:
- Standard binary search (finding an exact value): Return the index when found, return -1 when not found. Loop condition is
left <= right, return immediately when found. - Finding the first position equal to target: After finding
nums[mid] == target, you cannot return immediately. Instead, record the answer and continue searching in the left half (right = mid - 1). - Finding the last position equal to target: After finding it, record the answer and continue searching in the right half (
left = mid + 1). - Finding the first position greater than or equal to target: When
nums[mid] >= target, record the answer and search the left half. - Finding the last position less than or equal to target: When
nums[mid] <= target, record the answer and search the right half.
Mastering these variants is the key to binary search. It is recommended to understand and practice each one individually.
✨ Common Mistakes
- Using binary search on an unsorted array: Binary search requires the array to be sorted. If the data is unsorted, it must be sorted first.
- Mid calculation overflow:
(left + right) / 2may overflow when both left and right are very large. Useleft + (right - left) / 2instead. - Incorrect boundary updates:
left = midorright = midmay cause infinite loops (whenleft + 1 == right, mid always equals left). The correct approach is usuallyleft = mid + 1orright = mid - 1. - Confusing loop conditions:
left <= rightandleft < rightcorrespond to different binary search implementations and cannot be mixed. With<=, exiting the loop meansleft > right; with<, exiting the loop meansleft == right. - Forgetting to record the answer in variant implementations: In variants for finding the "first" or "last" position, you cannot return directly when a match is found. You need to record the current position first and then continue narrowing the range.