mid = floor(low+high)/2;
mid = floor(low+(high-low))/2; // avoids overflow
Two templates of writing BS (they output the exact same thing and differ by interval close []
vs [)
):
int low = 0, high = arr.size() - 1;
while(low <= high){
int mid = low + (high - low) / 2;
if(k == arr[mid]) return mid;
else if(k > arr[mid]) low = mid + 1;
else high = mid - 1;
}
// low > high here; precisely low = high + 1
// if method didn't return till now ofc
return -1;
int low = 0, high = arr.size(); // notice
while(low < high){ // notice
int mid = low + (high - low) / 2;
if(k == arr[mid]) return mid;
else if(k > arr[mid]) low = mid + 1;
else high = mid; // notice
}
// low == high here
// if method didn't return till now ofc
return -1;
NOTICE: after breaking out of the while
loop, the low
and high
values differ in these two approaches, this is important to find lower and upper bounds since we return low
there.
Optional Reading on above two templates of BS.
- Two ways to check value at mid:
- when you know what you’re looking for: check
mid
and skip it when moving to the other half by add or subtract1
to `mid (find k, lower_bound, upper_bound, BS on array) - when we aren’t looking for a specific value:
- set
low
tomid
to move to one half (ex - finding float root) -
low
andhigh
will converge to the same element eventually
- set
- when you know what you’re looking for: check
- Lower Bound: lower bound of
x
is the smallest indexi
such thatarr[i] >= x
. Ex - in[2 4 5]
, lower bound of3
is4
(not2
) and lower bound of4
is4
itself - Upper Bound: upper bound of
x
is the smallest indexi
such thatarr[i] > x
. Ex - in[2 4 5]
, upper bound of3
is4
and upper bound of4
is5
Note that Lower bound is equal to Upper bound if element x
is not present in the array. Also, there maybe no LB/UB (return -1
) if low
pointer crosses array bounds
Keep arr[mid] = k
condition on the direction we want to move in to skip duplicates. In lower bound we move leftwards in duplicates, in upper bound we move rightwards in duplicates. low
will always end up at the answer (rightwards element before condition is broken).
UB(e) - LB(e)
gives count of element (e
) in a sorted array. problem
LB, UB, floor, ceil - Striver’s strategy of storing in ans
on every potential candidate is very simple and intuitive than above low
pointer approach.
Ceil value is equal to the Lower Bound value, also if target element is present then floor = element = ceil
- Floor/Ceil of
x
: if target is4
,low
andhigh
will eventually converge at[2 5]
and after two more steps, we’ll have our greatest number less than x athigh
and lowest number greater than x atlow
. Take care of equal to cases and duplicates using strategy discussed above (for lower and upper bound) - Search Insert Position: insert position is lower/upper bound only, depends on where question wants us to insert if element is already present in array
- Find the first or last occurrence of a given number in a sorted array: CANNOT be solved using lower/upper bound or floor/ceil bcoz they guarantee a valid index as output and don’t return
-1
if element is not found in array- Find first position: on
arr[mid] == k
storeans = mid
and reduce search space to left array only (high = mid - 1
), rest is same as in normal BS - Find last position: on
arr[mid] == k
storeans = mid
and reduce search space to right array only (low = mid + 1
), rest is same as in normal BS
- Find first position: on
- Count occurrences of a number in a sorted array with duplicates: count will be
rightmost_index - leftmost_index
- use previous approach to find leftmost and righmost indexes
-
another way but linear TC: find any occurance of it using BS (if not found return
-1
), either checkidx == -1
then occurance is0
, or if a valididx
linearly scan its left half and right half for more occurances (time =O(n)
)
- Search in rotated sorted array (no duplicates) - we can’t tell which half to goto only by looking at
arr[mid]
andtarget
now, we can only do that in sorted arrays (or sorted half). Check which half is sorted - goto it only if target is in its range, otherwise goto the other half (even if unsorted) - iteratively looking for sorted half -
Search in rotated sorted array (duplicates present) - if
arr[mid] == k
is true then we’ve found our element, otherwise check conditionarr[mid] == arr[low] && arr[mid] == arr[high]
and if true dolow++; high--; continue;
, rest is the same as above - Find minimum in Rotated Sorted Array: leftmost element (
arr[low]
orarr[mid]
) in the sorted half will be the lowest, keep going to sorted halves and get minimum of it, and go to the other part - Find out how many times has an array been rotated: answer will be the index of the minimum or maximum element
- Check if array is sorted and rotated: use the property that both halves of the array are sorted (dividing point is the pivot, pivot = largest element), after finding the pivot, check sorted property of left half and right half manually (time =
O(n)
)
- Find peak element: check peaks among
arr[mid-1]
,arr[mid]
andarr[mid+1]
, keep moving in the direction of the greater element, if we reach a corner (arr[0]
orarr[n-1]
) then peak is that corner value itself. corner case is when there is just a single element in the array[2]
or we converged to a single element eventually (which will be one of the peaks), in that case don’t go inside loopwhile(low < high)
andreturn start;
at the end - Single element in a Sorted Array: first occurance is supposed to be at even index and other at odd, but after the single element, it will be vice versa. Goto
mid
and ifmid % 2 == 0
checkmid+1
, ifmid % 2 != 0
checkmid-1
. Go in the direction of single element everytime. Handle edge case of array having only 1 element using while loop rangelow < high
. - Find Kth element of two sorted arrays:
- count approach; mimic merge and count till K
- cutpoints approach,
k = cut1 + cut2
, takecut1
elements from one andcut2
from the other link- do BS on the smaller array only, compare
l1 r2 l2 r1
- do BS on the smaller array only, compare
- Median of two sorted arrays: use cutpoints approach above
left_half = (m + n + 1) / 2
, take care of cuts min/max, and median calc condition(s) in case total elements are even or odd link
- Root of any number (can be float) using BS: Time =
O(N * log(M x 10^d))
```cpp double eps = 1e-5; // upto 5 digits after decimal
while( (high - low) > eps ){
double mid = (low + high) / 2.0;
// set low = mid // or high = mid
}
return low; ``` —
Kth Missing Positive Number: find out no. of elements missing till current element = arr[i]-(i+1)
, answer will always be no. of elements present that are strictly less than arr[i] + k
i.e. i + k
when arr[i]-(i+1) >= k
is satisfied for the first time
- Shifting k
O(n)
solution - really smart one liner! - In BS solution we search on that
arr[i]-(i+1)
space and check it on everymid
and move accordingly, on==
condition we have exactlyk
missing elements in left ofmid
and our ans lies just belowarr[mid]
(ans = i+k
), we want LB (smallest index such thatarr[i]-(i+1) >= k
) so move leftwards!, then returnlow + k
after loop break
Split Array into K Subarrays: aka painter’s partition, book allocation, capacity to ship packages
low = max_element_of_array
andhigh = sum_of_all_elements_of_array
and keep searching for lower value that can accomodatek
max partitions (simulate) for eachmid
- on equal condition, move leftwards to minimize max sum, return
low
at the end
Row and Column Wise Sorted Matrix
Search in Row and Column Wise Sorted Matrix:
- staircase search in
O(m + n)
TC - rowwise and columnwise matrix after flattening isn’t a sorted 1D matrix so that won’t work
- the min in such matrix is
mat[0][0]
and max ismat[m-1][n-1]
so we can perform bs in that space and search elements in each row (m * log max(matEle)
)
Kth Element in Row and Column Wise Sorted Matrix problem
- same approach as above but count elements in each row using UB, and to find “actual” mid that is present in matrix do LB on search space (
m * log max(matEle)
) - LB since we’re trying to find smallest element (
mid
) in search space such that it gives usk
elements in the matrix and actually present in the matrix
Median of Row-wise Sorted Matrix: points to note - matrix is sorted only rowwise, not column wise, and r*c
is given to be odd
- find min and max elements of matrix from
0
th column andc-1
th column respectively - this is our median search space - perform binary search on this median space (calc
mid
) and for each row too use binary search to find numbers<= mid
(i.e. calc upper bound ofmid
for each row) - Nested Binary Search - use property that for an element
mid
to be median it needs to haver*c/2
elements to the left of itself. If number of elements aren’t sufficient or are excess, move left or right accordingly - on equality condition
countSmallEqual(mid) == r*c/2
, our ans is first element havingcountSmallEqual(mid) > r*c/2
(upper bound), so we move rightwards,low
will eventually converge to UB
Not From Sheet
Find the Duplicate Number: this can be optimally solved using BS or with Floyd’s cycle detection 2k23 notes link