[路飞]_二分查找以及算法题

346 阅读2分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

百度百科:在计算机科学中,二分搜索(英语:binary search),也称折半搜索(英语:half-interval search)、对数搜索(英语:logarithmic search),是一种在有序数组中查找某一特定元素的搜索算法搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

可以说二分查找是一种非常高效的搜索算法

二分算法的基本结构

function binarySearch(arr, target) {
  var left = 0,
    right = ...
  while (...) {
    var mid = (left + right) >> 1
    if (arr[mid] === target) {
        ...
    }
    else if (target < arr[mid]) {
        ...
    }
    else if (target > arr[mid]) {
        ...
    }
  }
  return ...
}

基本的二分算法

寻找一个数

二分查找的裸题 704. 二分查找

function binarySearch (nums, target) {
    if (!nums.length) return -1
    var left = 0, right = nums.length - 1
    while (left <= right) {
        var mid = (left + right) >> 1
        if (nums[mid] === target) return mid
        else if (nums[mid] < target) left = mid + 1
        else if (nums[mid] > target) right = mid - 1
    }
    return -1
};
//nums [-1,0,3,5,9,12]
//target 9
binarySearch(nums, target) // 4

思考一个问题:如果数组中存在相同的元素比如[-1,0,3,3,5,9,12],需要寻找3此时是希望返回左侧的还是右侧下标的元素既23

寻找左侧边界

function left_binarySearch (nums, target) {
    if (!nums.length) return -1
    var left = 0, right = nums.length - 1
    while (left < right) {
        var mid = (left + right) >> 1
        if (nums[mid] === target) right = mid
        else if (nums[mid] < target) left = mid + 1
        else if (nums[mid] > target) right = mid
    }
    return left
};
//nums [-1,0,3,3,5,9,12]
//target 3
left_binarySearch(nums, target) // 2

寻找右侧边界

function right_binarySearch (nums, target) {
    if (!nums.length) return -1
    var left = 0, right = nums.length - 1
    while (left < right) {
        var mid = (left + right) >> 1
        if (nums[mid] === target) left = mid + 1
        else if (nums[mid] < target) left = mid + 1
        else if (nums[mid] > target) right = mid
    }
    return left - 1
};
//nums [-1,0,3,3,5,9,12]
//target 3
right_binarySearch(nums, target) // 3

详细参考

小范围优化

function binarySearch (nums, target) {
    if (!nums.length) return -1
    var left = 0, right = nums.length - 1
    while (right - left > 3) { // 如果左右小于3
        var mid = (left + right) >> 1
        if (nums[mid] === target) return mid
        else if (nums[mid] < target) left = mid + 1
        else if (nums[mid] > target) right = mid - 1
    }
    // 小范围循环
    for (var i = left; i <= right; i++) {
        if (numbs[i] === target) return i
    }
    return -1
};
//nums [-1,0,3,5,9,12]
//target 9
binarySearch(nums, target) // 4

二分算法应用

633. 平方数之和

/**
 * @param {number} c
 * @return {boolean}
 */
var judgeSquareSum = function(c) {
    if(c === 0) return true
    for(var i = 0; i < Math.sqrt(c); i++) {
        var left = i, right = Math.floor(Math.sqrt(c))
        // 二分
        while(left <= right) {
            var mid = (left + right) >> 1
            var rst = i*i + mid*mid
            if(rst === c) return true
            else if(rst < c) left = mid + 1
            else if(rst > c) right = mid - 1
        }
    }
    return false
};

34. 在排序数组中查找元素的第一个和最后一个位置

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function (nums, target) {
  var ret = [-1, -1]
  ret[0] = binarySearch(nums, target)
  if (ret[0] == nums.length || nums[ret[0]] != target) {
    return [-1, -1]
  }
  ret[1] = binarySearch(nums, target + 1) - 1//查找第一个比target大的位置,前一位就是target结束位置。如果是最后一位返回 nums.length -1
  return ret
};
// 查找第一个大于等于x的值
var binarySearch = function (nums, x) {
  var head = 0,
    tail = nums.length - 1,
    mid
  while (tail - head > 3) {
    mid = (head + tail) >> 1
    if (nums[mid] >= x) tail = mid
    else head = mid + 1
  }
  for (var i = head; i <= tail; i++) {
    if (nums[i] >= x) return i
  }
  return nums.length //最大长度下一位方便求值
}

--未完待续--