文章目录

  • 前言
  • 一、二分查找
  • 二、第一个错误的版本
  • 三、搜索插入位置
  • 总结

前言

Leetcode算法系列:https://leetcode-cn.com/study-plan/algorithms/?progress=njjhkd2

简单介绍总结一下二分查找相关的算法题:

一、二分查找

题目链接:https://leetcode-cn.com/problems/binary-search/

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

思路:直接采用通用的二分查找算法即可:

class Solution {public int search(int[] nums, int target) {int start=0,end=nums.length-1,mid;while(start<=end){mid=(start+end)/2; // 最好改为:mid = start+(end-start)/2;if(nums[mid]==target)return mid;else if(nums[mid]<target)start=mid+1;elseend=mid-1;}return -1;}
}

1,取 mid 值时,采用 mid = start+(end-start)/2; 可以避免当 start 和 end 很大时造成的整数(int)越界。
      2,循环结束条件为 start<=end,所以在 while 循环退出时有 start>end,(在此为 start=end+1)。
      3,二分查找的时间复杂度为 O(logn),因为每次循环都会将待处理数组的规模缩小一半。

二、第一个错误的版本

题目链接:https://leetcode-cn.com/problems/first-bad-version/

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

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

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

思路:保持之间的二分查找框架不变,修改循环退出条件为当前版本正确且上一个版本错误,

public class Solution extends VersionControl {public int firstBadVersion(int n) {if(isBadVersion(1))return 1;int start=2,mid; //区间为[2,n].while(start<=n){  //还是按照二分查找的思路来做mid=start+(n-start)/2;if(!isBadVersion(mid))   //缩小区间到[mid+1,n]start=mid+1;else if(!isBadVersion(mid-1))    //如果mid为true,mid-1为false,返回mid即可return mid; else    //如果mid-1不是false,缩小区间到[start,mid-1]n=mid-1;}return -1;}
}

缺点时要调用两次 isBadVersion函数。

Version2:修改循环判定条件为start<end,在循环退出时的 start 或 end 为我们感兴趣的下标值。并采用合理的缩小规模方式在循环内仅调用一次 isBadVersion 函数。如下:

 public class Solution extends VersionControl {public int firstBadVersion(int n) {int start=1,mid;while(start<n){mid=start+(n-start)/2;if(!isBadVersion(mid))start=mid+1;elsen=mid;}return start;}
}

上述算法看起来很巧妙,甚至成功的有点侥幸,因为在每次计算 mid 值时,由于向下取整,所以有时候会出现 mid==start 出现,而不会存在 mid==n 出现。因此令 n=mid;这样在每次循环时区间规模总会缩小,直至得到最终结果。

在缩小区间时,最好不要采用 start==mid,很有可能区间不会缩小,陷入死循环。比如当要求找到最后一个正确的版本时会发生这种情况。

三、搜索插入位置

题目链接:https://leetcode-cn.com/problems/search-insert-position/

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

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

思路:采用通用的二分查找框架,如果目标值存在于数组中,由 mid 给出其返回下标;如果不存在的话,由 start 或 end+1 给出返回下标。

class Solution {public int searchInsert(int[] nums, int target) {int start=0,end=nums.length-1,mid;while(start<=end){mid=start+(end-start)/2;if(nums[mid]==target)return mid;else if(nums[mid]<target)start=mid+1;elseend=mid-1;}return start;   //关键点在于确定最后一个查找区间和target之间的关系。//return end+1;}
}

由 start 或 end+1 给出返回值下标的原因在于:在一个不含目标值的升序数组中采用通用的二分查找算法查找 target 的位置,在循环结束后 end 处的值刚好小于 target;start 处的值刚好大于 target。 比如对于数组 [1,3,4,6,7],查找 5 所在位置:循环结束后 start =3,end = 2。

Version2:修改循环判定条件为start<end,在循环退出时的 start 或 end 为我们感兴趣的下标值。如下:

    public int searchInsert(int[] nums, int target) {int end=nums.length-1,start=0,mid;// 特殊判断if (nums[end] < target) return end+1;// 程序走到这里一定有 nums[end] >= target,保证插入位置在区间 [start..end]while(start<end){mid=start+(end-start)/2;if(nums[mid]<target)start=mid+1;// 下一轮搜索的区间是 [mid + 1..end]elseend=mid;// 下一轮搜索的区间是 [start..mid]}return end;}

和 二、查找错误的版本类似:在循环中令 end=mid 来保证循环执行结束。


总结

通用的二分查找判定条件为 start<=end,意味着结果在循环中给出;当采用 start<end 时,结果在循环执行后由 start 或 end 给出。

LeetCode算法题4:二分查找及扩展应用相关推荐

  1. leetcode刷题笔记——二分查找

    leetcode刷题笔记--二分查找 目前完成的贪心相关的leetcode算法题序号: 中等:80,81 困难:4 来源:力扣(LeetCode) 链接:https://leetcode-cn.com ...

  2. LeetCode简单题之二分查找

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

  3. LeetCode刷题笔记 二分查找 局部有序

    二分查找的局部有序情况 ​ 我们已经知道二分查找是一种在有序数组中查找某一特定元素的查找算法. ​ 那如果一个数组不是整体有序,而是局部有序呢?这时我们就可以通过分治策略,我们在局部有序的区间内进行二 ...

  4. 经典算法题:二分查找

    二分查找 题目来源于京东校园招聘笔试真题 题目描述 有一个有序表为 {1,5,8,11,19,22,31,35,40,45,48,49,50} ,当二分查找值为 48 的结点时,查找成功需要比较的次数 ...

  5. 算法题3 二分查找法

    快速查找:二分查找法 有序数字:3,5,8,10,14,18,19,20,34,58 package com.interview;public class BinarySearch {public s ...

  6. LeetCode算法题整理(200题左右)

    目录 前言 一.树(17) 1.1.后序遍历 1.2.层次遍历 1.3.中序 1.4.前序 二.回溯(20) 2.1.普通回溯 2.2.线性回溯:组合.排列.子集.分割 2.3.矩阵回溯 三.二分查找 ...

  7. Leetcode算法题:两个有序数组求中位数

    Leetcode算法题:两个有序数组求中位数 要求时间复杂度为O(log(m+n)) 思路: 暴力解决:合并数组并排序,简单且一定能实现,时间复杂度O(m+n) 由于两个数组已经排好序,可一边排序一边 ...

  8. 5、leetcode剑指offer53 二分查找之0~n-1缺失的数字**

    leetcode剑指offer53 二分查找之0~n-1缺失的数字 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0-n-1之内.在范围0-n-1内的n个数字中有且只有一个 ...

  9. LeetCode算法题-Nth Digit(Java实现)

    这是悦乐书的第215次更新,第228篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第83题(顺位题号是400).找到无限整数序列的第n个数字1,2,3,4,5,6,7,8 ...

  10. LeetCode算法题-Reverse Linked List(Java实现)

    这是悦乐书的第192次更新,第195篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第51题(顺位题号是206).反转单链表.例如: 输入:1-> 2-> 3- ...

最新文章

  1. 企业部署Linux应用将拥有更低的整体拥有成本
  2. window环境使用C++实现WebSocket
  3. C语言学习之用筛选法求100之内的素数
  4. 带宽测量:pathload编译及运行
  5. Android之自定义属性
  6. 阿里云DDoS高防 - 访问与攻击日志实时分析(四)
  7. C语言灵魂——算法!
  8. js 判断移动端还是pc端,ios或者android
  9. Android操作系统手机遇冷 国外辉煌国内难现
  10. [转载] Python里面numpy库中zeros()的一些问题
  11. 2020年最新世界地图_2020世界地图下载
  12. java实现将.acc格式转化为mp3格式
  13. Vue含表情评论回复组件
  14. vscode 折叠所有区域代码快捷键
  15. 苹果双系统怎么切换_电脑双系统如何安装,使用小白一键重装系统
  16. 华为狼文化被喷,任正非回应:华为没有996,更没有007!
  17. 3.1 数据报表之Excel操作模块 XlsxWriter
  18. 在线语音合成 5-1
  19. [报错] TypeError: run() argument after * must be an iterable, not int
  20. 揭秘:蓝光光碟“造”太阳能电池的神奇之处

热门文章

  1. W - Pasha and Phone CodeForces - 595B (收益颇丰的数学题
  2. redis面试问题(二)
  3. 图论数学:矩阵树定理
  4. HBase - 数据写入流程解析
  5. Python常用模块——目录
  6. Fibonacci数列时间复杂度之美妙
  7. centos7下 vsftpd初使用
  8. FreeSwitch安装和配置记录
  9. Java中关于==和equal的区别 以及equals()方法重写
  10. Spring Security 2 配置精讲