Fundamentals of binary search algorithm

Keywords: Algorithm data structure leetcode

In binary search, the definition of the search interval of the target element is very important, and the definitions of different intervals are written differently. Because the search interval is iterative, it is very important to determine the search range, mainly the opening and closing of the left and right intervals. The opening and closing are different, and the corresponding iteration methods are different. There are two methods:
left,right
Left close right open

The idea of dichotomy is very simple, because the whole array is ordered, and the array is incremented by default.
1. First, select the number in the middle of the array and compare it with the target value to be found
2. If equality is the best, you can directly return the answer
3. If not equal
(1) If the middle number is greater than the target value, all numbers to the right of the middle number are greater than the target value and are excluded
(2) If the middle number is less than the target value, all numbers to the left of the middle number are less than the target value and are excluded
Dichotomy is a fast exclusion search in this way

Example: given an n-element ordered (ascending) integer array nums and a target value target, write a function to search the target in nums. If the target value exists, return the subscript, otherwise return - 1.

function search(nums, target){
	let low = 0, high = nums.length - 1;
    while (low <= high) {
        const mid = Math.floor((high - low) / 2) + low;
        const num = nums[mid];
        if (num === target) {
            return mid;
        } else if (num > target) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return -1;

}

Note: whether the length of the array is odd or even does not affect the problem of how to exclude. It is just to exclude one more number or one less number. What really affects is whether the middle number should be added to the next search, that is, the boundary problem.

The two most important points of dichotomy:

  • Is the relationship between left and right in the while loop left < = right or left < right
  • Is the relationship between middle and right in the iteration process right = middle - 1 or right = middle

1: Left closed right closed

  • Use while (left < = right) for loop conditions
  • If (Num [middle] > target), right should be assigned to middle - 1. Because the current num [middle] must not be the target, the number above the middle position needs to be discarded, so the next search range is [left, middle - 1]

Example:

function search(nums, target){
	let low = 0, high = nums.length - 1;
    while (low <= high) {
        const mid = Math.floor((high - low) / 2) + low;
        const num = nums[mid];
        if (num === target) {
            return mid;
        } else if (num > target) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return -1;

}

2: Left closed right open

  • Use while (left < right) for loop conditions
  • If (Num [middle] > target), right = middle, because the current num [middle] is greater than
    target does not meet the conditions and cannot get middle, and the definition of the interval is [left, right]. Just the definition of the interval cannot get right,
    So right is assigned to middle.

Example:

function search(nums, target){
	let low = 0, high = nums.length;
    while (low < high) {
        const mid = Math.floor((high - low) / 2) + low;
        const num = nums[mid];
        if (num === target) {
            return mid;
        } else if (num > target) {
            high = mid ;
        } else {
            low = mid + 1;
        }
    }
    return -1;

}

3: Examples
1: Finds the first and last positions of elements in a sorted array

const binarySearch = (nums, target, lower) => {
    let left = 0, right = nums.length - 1, ans = nums.length;
    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        if (nums[mid] > target || (lower && nums[mid] >= target)) {
            right = mid - 1;
            ans = mid;
        } else {
            left = mid + 1;
        }
    }
    return ans;
}

function searchRange(nums, target) {
    let ans = [-1, -1];
    const leftIdx = binarySearch(nums, target, true);
    const rightIdx = binarySearch(nums, target, false) - 1;
    if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] === target && nums[rightIdx] === target) {
        ans = [leftIdx, rightIdx];
    } 
    return ans;
};

2: Square root of X

function mySqrt(x){
	 if (x < 2) return x
     let left = 1, mid, right = Math.floor(x / 2);
     while (left <= right) {
        mid = Math.floor(left + (right - left) / 2)
        if (mid * mid === x) return mid
        if (mid * mid < x) {
            left = mid + 1
        }else {
            right = mid - 1
        }
     }
     return right
}

3: Search two-dimensional matrix

function search(nums, target){
	let low = 0, high = nums.length - 1;
    while (low <= high) {
        const mid = Math.floor((high - low) / 2) + low;
        const num = nums[mid];
        if (num === target) {
            return true;
        } else if (num > target) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return false;
}

function searchMatrix(matrix,target){
	let lowArr = 0, highArr = matrix.length - 1; 
    while (lowArr <= highArr) {
        const midArr = Math.floor((highArr - lowArr) / 2) + lowArr;
        const len = matrix[midArr].length-1;
        if (matrix[midArr][0] <= target && matrix[midArr][len] >= target) {
           return search(matrix[midArr],target)
        }else if (matrix[midArr][0] > target) {
             highArr = midArr -1;
        }else{
            lowArr = midArr + 1;
        }
    }
    return false
}

Posted by audiodef on Sun, 19 Sep 2021 11:05:30 -0700