what to think when you write binary search
Binary search
binary search is prety tricky and have a lot hidden dents, here is my summary.
Common problem
given a non-descending array, find element with value m in the array.
below is the classic c code
1 | int binary_search(int *A, int n, int target) |
there are several places you need to consider, which is shown below :
there are totally 6 places you need to be aware whey you write to binary search.
for 1 and 2, I choose the close bounary 0 and n-1.
for 3, I choose
low <= high
,why? let’s assume test case[3, 5, 7, 9, 10]
, assume I search target = 10,- low = 0, mid = 2, high = 5, 10 > a[mid]= 7, so low = 3.
- low = 3, mid = 4, high = 5, 10 > a[mid] = 9, so low = 10
- if the while loop check is
low < high
, at this time, the loop would terminate, you didn’t get the newmid
and compare it with the target.
for place 4, it is also very tricky. Generally, people like to use
int mid = (low + high)>>1
, but there are some risks there. if low and high is big int, then the sum would possibly overpass theINT_MAX
. so it is safe to use the format at place 4. but why not useint mid = high - (high-low) >> 1
? In fact, in some case, we have to use it that way.for place 5 and place 6, they have differnet form, you might use
low = mid
orlow = mid+1
, for high, it might behigh = mid -1
orhign = mid
, it is case by case.
basically, all the binary search problem is somehow related to how to find the proper combination for the 6 places. So Here I will give example.
Problem 1
given a sorted(non-ascending) array A, it may contains repeated elements, get the smallest i which make
A[i]=target
, if not, return -1.
1 | int searchFirstPos(int A[], int n, int target) |
question 1 : at the comment 1, can I use low <= high
?
answer : you can not. assume you have array A = [2,2], target = 2
, the loop step is like this :
- low = 0, high = 1, mid = 0.
- since
A[mid] ==target
, we gothigh = mid = 0
. at this time,low == high
, continue loop. low = 0, high=mid=0
=>mid=0
, soA[mid]==targt
, infinite loop.
see the leet code issue - Search Insert Position
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.
Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0
code :
1 | class Solution { |
Problem 2
given a sorted(non-descending) array, may contains repeated elements, find the biggest i which makes
A[i] = target
, if not , return -1.
1 | int searchLastPos(int A[], int n, int target) |
question 1 : why we cannot use int mid = low+((high-low)>>1);
answer : suppose you have test case A = [1,2], target = 2
- low = 0, high = 1, mid = 0
- A[mid] = 1 < target = 2, so low = 0 again.
- infinite loop.
insted of int mid = low+((high-low+1)>>1);
, I would rather use int mid = high - ((high - low)>>1)
, which looks better.
so the code becomes like this :
1 | int searchLastPos(int A[], int n, int target) |
In fact, problme 2 is similar to the get_upperbound
Problem 3
given a sorted array, may contains duplicates, find a biggest i which makes A[i] < target, return i, if not, return -1.
problem 3 is ask for A[i] < target
, problme 2 is aksing for A[i]=target
, this is the difference.
1 | int searchLastPosLessThan(int A[], int n, int target) |
notice, code 1 2,3 and 4 is differnt from the above problem. need to be very careful.
Problem 4
given a sorted array, may contains duplicates, find a smallest i which makes A[i] > target, return i, if not, return -1.
1 | int searchFirstPosGreaterThan(int A[], int n, int target) |
Problem 5
given a sorted array (non-descending), may contains duplicates, try to find out how many times target appears at the array.
1 | int count(int A[], int n, int target) |
there is also a similar problme in leet code : Search for a Range
Given a sorted array of integers, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].
1 | class Solution { |