javascript算法之从会用到理解 - 二分法


活动地址:CSDN21天学习挑战赛

前言

某种算法的实际应用,核心就是要找到当前算法的使用前提,基于其算法核心,对数据进行重组、改造,最终输出;

二分法

二分法顾名思义,通过每次取中间数进行对比,从而得到想要的数据,这就不必赘述了吧!

下面来讲一下二分法的算法核心:

  • 找到中间值
  • 与目标值对比,按需求缩小数组范围
  • 最终得到一个元素,即为所求值

常用方案:

  • 数组必为有序数组;
  • 确定数组中没有相同元素;

则处理步骤为:

  1. 确定为有序数组,
  2. 利用三个数进行查找,所以先确定三个值,开始值、末尾值、中间值;中间值需要进行计算得来;
  3. 将中间值与目标值进行比较;
  • 中间值 < 末尾值/目标值,以中间值的下一位作为末尾值,开始值不变;
  • 中间值 > 末尾值/目标值,以开始值的前一位作为开始值,末尾值不变;
  • 目标值 = 中间值,则为想要的结果;

🐲第一个错误的版本

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

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

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

示例 1:
输入:n = 5, bad = 4
输出:4

解释:
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。

题目来源:https://leetcode.cn/problems/first-bad-version

分析:
由于此数组本身就是数字,且自增,所以,可以设置开始值为left = 1,末尾值right=n,中间值mid为向下取整的中间数;然后,就利用中间值,判断是否为正确版本,是正确版本,则正确区间为[mid+1, right],不是正确版本,则
正确区间为 [left, mid];当left=right,则输出正确值;

var solution = function(isBadVersion) {
  return function(n) {
        let left = 1, right = n;
        while (left < right) { // 循环直至区间左右端点相同
            const mid = Math.floor(left + (right - left) / 2); // 防止计算时溢出
            if (isBadVersion(mid)) {
                right = mid; // 错误版本,答案在区间 [left, mid] 中
            } else {
                left = mid + 1; //正确版本 答案在区间 [mid+1, right] 中
            }
        }
        // 此时有 left == right,区间缩为一个点,即为答案
        return left;
    };
};

🐲寻找旋转排序数组中的最小值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:
输入:nums = [3,4,5,1,2]

输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

题目来源:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array

分析:
由于目标值可能大于最大的数组元素,所以right值为数组长度,而不是数组的长度-1;

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

结语

二分法,主要逻辑就是通过中间值和目标值的比较,然后缩小数组范围,最终得到答案,从问题中提炼出这个含义,就可以进行二分法的使用了,当然,在某些情况下,二分法也并不算得上最优解,按需取用即可!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乾复道

与君共勉

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值