Thoughts about Binary Search (From LeetCode 378)
inspired by Leetcode 378
The key point for any binary search is to figure out the “Search Space”. For me, I think there are two kind of “Search Space” – index and range(the range from the smallest number to the biggest number). Most usually, when the array is sorted in one direction, we can use index as “search space”, when the array is unsorted(or sorted in more than one direction like leetcode 378) and we are going to find a specific number, we can use “range”.
Let me give you two examples of these two “search space”
index – A bunch of examples – https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/ ( the array is sorted)
range – https://leetcode.com/problems/find-the-duplicate-number/ (Unsorted Array) leetcode378 (sorted in two directions)
both of these problems can be solved in binary search.
If you are gonna ask me: “what exactly is search in range means?”, I can give you the answer by showing the solution of leetcode378
public class Solution {
public int kthSmallest(int[][] matrix, int k) {
int lo = matrix[0][0], hi = matrix[matrix.length - 1][matrix[0].length - 1] + 1;//[lo, hi)
while(lo < hi) {
int mid = lo + (hi - lo) / 2; //this mid is the key point of "mid in range" instead of "mid in index"
int count = 0, j = matrix[0].length - 1;
for(int i = 0; i < matrix.length; i++) {
while(j >= 0 && matrix[i][j] > mid) j--;
count += (j + 1);
}
if(count < k) lo = mid + 1;
else hi = mid;
}
return lo;
}
}
however, this solution may works fine, but very difficult to understand, the first is why we have to return lo since lo is not necessary the element in matrix.
so I find a better explain version:
public int kthSmallest(int[][] matrix, int k) {
// num of rows and cols in matrix
int rows = matrix.length, cols = matrix[0].length;
// get the lowest and highest possible num, will shrink search space according to the two nums
// [lo, hi] is our initial search range
int lo = matrix[0][0], hi = matrix[rows - 1][cols - 1] ;
while(lo <= hi) {
int mid = lo + (hi - lo) / 2;
int count = 0, maxNum = lo;
// for each row, we r going to find # of nums < mid in that row
for (int r = 0, c = cols - 1; r < rows; r++) {
while (c >= 0 && matrix[r][c] > mid) c--; // this row's c has to be smaller than the c found in last row due to the sorted property of the matrix
if (c >= 0) {
count += (c + 1); // count of nums <= mid in matrix
maxNum = Math.max(maxNum, matrix[r][c]); // **mid might be value not in matrix, we need to record the actually max num;** //this comment is super important
}
}
// adjust search range
if (count == k) return maxNum;
else if (count < k) lo = mid + 1;
else hi = mid - 1;
}
// the following Q&A perfectly answer my doubts
// 1) Q: Why we return lo at the end:
// A: Here lo=hi+1, for hi, we found <k elems, for lo, we found >=k elem, lo must have duplicates in matrix, return lo
// 2) Q: Why lo exist in the matrix
// A: for lo which is only 1 more than hi, we could find some extra nums in matrix so that there r >=k elems, so lo it self must exist in the matrix to meet the requirement
return lo;
}

浙公网安备 33010602011771号