Problem¶
Find a element x
in a sorted array arr
For easier to follow:
1. We assuming arrayarr
is value is sorted from the lowest to highest.
2. The array is zero-index (arr
start from 0)
arr = [1,2, 2, 2, 2, 3, 4, 6, 8, 9, 142, 142, 142, 142, 255, 255, 255, 567, 1275, 1275, 1275, 2547, 2547, 5458, 9722, 92124]
x = 567
Solve¶
What happening?¶
We leverage on the characteristic of a sorted array, where a index i
element always have bigger or equal value than element with smaller index than i
.
and revert
This mean, if we access a value <any>
of the arr
, we know that the finding value x
is either in the left, or in the right of the <any>
element.
Pseudo code¶
While there is many way to choose the value <any>
in arr
, we specifically choose the middle of arr
. By splitting at the middle, we can eliminate the most of arr
in one comparing session.
- Start with the full array
arr
, find the middle of the arrayarr
, we calling itmid
point, with valuearr[mid]
- Base on the comparing result of
x
andarr[mid]
, We narrowing down arrayarr
for searching:- If
x == arr[mid]
, returnTrue
as we foundx
- If
x < arr[mid]
,arr
can be narrowing down toarr[0..mid-1]
, as all value ofarr[mid .. n]
is greater thanx
- If
x > arr[mid]
,arr
can be narrowing down toarr[mid+1..len(arr) - 1]
, as all value ofarr[0 .. mid]
is less thanx
- If
- Repeat the process with our new narrowed array
arr
This result on a O(log n) time complexity
Actual Implement¶
Personal preference¶
O(log n)
There is something call Off by one error causing a lot of debug time, so my general take on binary search is always:
(left, right) = (lowest, highest) = (-1, len(arr))
(both left and high is not inclusive in the array from the beginning)
Why? There is several advantage problem related to binary search, that we will stump on:
- Find the first appearance of
x
in array - Find the last appearance of
x
in array - Find the all appearance of
x
in array - Find the position to insert
x
into array so that arrayarr
still sorted
By using both left
and right
not in the array give me better control on how I want to lane left
and right
pointer in to array. This is a example on Find the all appearance of x
in array arr
:
isFound
tell us ifx
inarr
or not- Where
lastPosition
tell you the element with the biggest position inarr
that havex
value
from math import trunc, log
def binarySearch(arr, x):
l, r = -1, len(arr)
n = len(arr)
logn = trunc(log(n+2,2))+1
for _ in range(logn):
m = (l + r) // 2
if l == r-1:
break
if x < arr[m]:
r = m
else:
l = m
assert l == r-1
return x == arr[l], l
arr = [1, 2, 2, 2, 2, 3, 4, 6, 8, 9, 142, 142, 142, 142, 255, 255, 255, 567, 1275, 1275, 1275, 2547, 2547, 5458, 9722, 92124]
x = 567
isFound, lastPossition = binarySearch(arr, x)
print(isFound, lastPossition)
Example:¶
Problem | Last update |
---|---|
74. Search a 2D Matrix | 8:52 PM - October 02, 2023 |
84. Largest Rectangle in Histogram | 8:52 PM - October 02, 2023 |
81. Search in Rotated Sorted Array II | 8:52 PM - October 02, 2023 |
274. H-Index | 8:52 PM - October 02, 2023 |
Typescript implementation¶
O(log n)
Not thing fancy, just pain
- For divining, JavaScript force us to use
(float)
division result, we have to useMath.floor()
(do not useMath.trunc()
) - The implement just focus on finding the value, so it return on found value immediately
export default function bs_list(haystack: number[], needle: number): boolean {
let l = -1;
let r = haystack.length;
let m = 0;
while (true) {
m = Math.floor((l + r) / 2);
if (haystack[m] == needle)
return true;
if (l == m)
break;
if (haystack[m] < needle) {
l = m;
} else {
r = m;
}
}
return false
}
Created : August 28, 2023