分享题解04:二分法

二分查找

二分查找是一种基于比较目标值和数组中间元素的教科书式算法。

  • 如果目标值等于中间元素,则找到目标值。
  • 如果目标值较小,继续在左侧搜索。
  • 如果目标值较大,则继续在右侧搜索。

算法步骤:

  • 初始化指针 left = 0, right = n - 1。
  • 当 left <= right: 比较中间元素 nums[pivot]和目标值 target 。
  • 如果 target = nums[pivot],返回 pivot。
  • 如果 target <nums[pivot],则在左侧继续搜索 right = pivot - 1。
  • 如果 target >nums[pivot],则在右侧继续搜索 left = pivot + 1。

作者:LeetCode
链接:https://leetcode-cn.com/problems/binary-search/solution/er-fen-cha-zhao-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标准二分法问题

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-search
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

第一种解法:暴力循环

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    var flag = 1;
    var index = undefined
    for(var i = 0; i < nums.length; i++){
        
        if(nums[i] == target){
            flag = 0;
            index = i;
            break
            //return i
        }else{
            continue
        }
    }
    if(!flag){
        return index
    }
    else{
        return -1
    }
};

仔细体会一下这里 flag 的用处,这种用法也是我在查看其他题解的过程中学习的,对于需要判断标志的情形均可以使用

第二种解法:二分法

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    var first = 0;
    var last = nums.length - 1; 
    while(first <= last){
        var mid = Math.floor((first + last) /2);
        if( nums[mid] < target){
            first = mid + 1;
        } 
        if(nums[mid] == target){
            return mid ;
        } 
        if(nums[mid] > target){
            last = mid - 1;
        }  
    }
    return -1;
};```

```javascript
在这里插入代码片

二分法变形——第一题:

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-bad-version
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for isBadVersion()
 * 
 * @param {integer} version number
 * @return {boolean} whether the version is bad
 * isBadVersion = function(version) {
 *     ...
 * };
 */

/**
 * @param {function} isBadVersion()
 * @return {function}
 */
var solution = function(isBadVersion) {
    /**
     * @param {integer} n Total versions
     * @return {integer} The first bad version
     */
    return function(n) {
    	// 代码写在这里
        var left = 1;
        var right = n;
        while(left <= right){
            var mid = Math.floor((left + right)/2);
            if(isBadVersion(mid) == false){
                // 错误版本在 mid 后面,包含 mid
                if(isBadVersion(mid + 1) == true){
                    return mid + 1
                }
                else{
                    //排除 mid 的情形,也就是 错误版本在 mid 后面
                    left = mid + 1;
                }
            }
            if(isBadVersion(mid) == true){
                //  错误版本在 mid 之前,包含 mid
                if(isBadVersion(mid - 1) == false){
                    return mid
                }
                else{
                    //排除 mid 的情形,也就是 错误版本在 mid 前面
                    right = mid - 1;
                }
            }
        }
    };
};

二分法变形——第二题:

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var searchInsert = function(nums, target) {
    var left = 0;
    var right = nums.length - 1; 
    var ans = nums.length;
    while(left <= right){
        var mid = Math.floor(left + (right - left)/2); 
        if (target <= nums[mid]) {
            ans = mid;
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return ans;


};

总结
对于二分法问题:

  1. 首先肯定是要知道这个问题是二分法问题;
  2. 关于区间的选择问题,是[left,right]还是[left,right),推荐使用闭区间,比较简单;原因有二:其一是使用左闭右开的区间,在设置while循环的判断条件时有所不同。其二是mid包含在哪个部分,就在哪个需要单独讨论 mid 的情况;
  3. 关于 mid 的求解过程,以上两种变形写出了两种方式:其一是left + (right - left)/2);另一种是(left + right)/2,从数学角度上来说,两种并无区别,我自己也并没有发现区别,但是在写程序时,写 ** (left + right)/2** 偶尔会报错,查看题解时,大家都这么写left + (right - left)/2)。说法是left + right会导致溢出(超过数组索引值范围)。推荐写法:left + (right - left)/2)。

不足之处欢迎大家批评指正。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值