文章目录

  • 1. 二分法查找法的基本思想
  • 2. 二分查找的时间复杂度
  • 3. 二分查找的几个模版
    • 3.1 模板一: 标准的二分查找
    • 3.2 模板二: 二分查找边界(左边界, 右边界, 或是左右边界)
      • 3.2.1 对于二分法查找左边界的模板
      • 3.2.1 对于二分法查找右边界的模板
    • 3.2 模板三: 二分查找极值点
  • 4. 总结

1. 二分法查找法的基本思想

  • 二分法其实就是使用了分治法的思想;
  • 二分法的基本思想是将n个元素分成大致相等的两部分, 取nums[mid] 与 target 做比较:
    • 如果 target = nums[mid], 则找到target, 运行结束, 返回mid;
    • 如果 target > nums[mid], 则只需要在数组nums的右半部分继续搜索 target即可;
    • 如果 target < nums[mid], 则只需要在数组nums的左半部分继续搜索 target即可;

2. 二分查找的时间复杂度

二分查找法的时间复杂度即为 while循环的次数

总共有n个元素, 不断的折半循环下去就是 n, n/2, n/4,… n/2k (这些都是每次需要进行比较操作的元素个数), 其中k是循环的个数;

3. 二分查找的几个模版

一般而言,当一个题目出现以下特征之一时, 我们应该联想到它是否能够使用二分查找解题:

  1. 待查找的数组有序或局部有序
  2. 题目要求我们解题的时间复杂度低于 O(n), 或者直接就要求时间复杂度为O(log n)

二分查找有很多变体, 使用时需要注意查找条件, 判断条件左右边界的更新方式, 三者配合不好就很容易出现死循环或遗漏区间, 这也是因此二分法总被人说"十个二分九个错"的一大原因;

  • 下面我们将介绍几种二分查找的模板:

    • 标准的二分查找
    • 二分查找左边界
    • 二分查找右边届
    • 二分查找左右边界
    • 二分查找极值点

3.1 模板一: 标准的二分查找

标准的二分查找的使用场景(也是算法题目的解题关键字): 数组元素有序且不可重复

我们以经典例题: lt.704-二分查找 为例, 给出这种要求数组元素有序不可重复的二分查找的模板:

//“搜索一个数,如果存在,返回其索引,否则返回 -1class Solution {public int binarySearch(int[] nums, int target) {//定义每次遍历的左右端点int left = 0;int right = nums.length - 1;//开始遍历while(left <= right){//定义中值, 它是判断截取数组前半段还是半段的依据int mid = left + (right - left)/2;if(nums[mid] == target){return mid;}else if(nums[mid] > target){//截取前半段right = mid - 1;}else if(nums[mid] < target){//截取后半段left = mid + 1;}}return -1;}
  • 循环条件: left <= right
  • 中间位置计算: mid = left + ((right - left)) >> 1 (位移 >>1 就是 除法运算 /2, 比除法效率稍高一些)
  • 左边界更新: left = mid + 1
  • 右边界更新: right = mid - 1
  • 返回值: mid-1

为什么推荐使用左闭右闭解二分查找的题目

3.2 模板二: 二分查找边界(左边界, 右边界, 或是左右边界)

  • 整这种一套一个模板的真的浪费精力, 直接一招鲜吧:

laxi的一篇文章

  • 对于二分查找类的问题, 我们统一使用:
//左右边界
int left = 0;
int right = nums.length - 1;//循环条件
while(left <= right){int mid = left + (right - left) >> 1;//边界更新方法根据题目要求...
}

3.2.1 对于二分法查找左边界的模板

public int bsLeft(int[] nums, int target){int left = 0;int right = nums.length -1;while(lef <= right){int mid = left + ((right - left)  >> 1);  // >>1 是位运算符, 相当于 /2, 性能比 /2 稍快if(nums[mid] < target){left = mid + 1;}else if (nums[mid] > target){right = mid - 1;}else if(nums[mid] == target) {//由于是查找左边界, 所以查找到于target相等的元素时, 仍需要向左移动right = mid - 1; // 持续向左 缩短右边界} }//left 越界判断,,根据具体题目判断. (target > nums所有if(left >= nums.length || nums[left] != target){//根据具体题目判断.}
}

3.2.1 对于二分法查找右边界的模板

public int bsLeft(int[] nums, int target){int left = 0;int right = nums.length -1;while(lef <= right){int mid = left + ((right - left)  >> 1);  // >>1 是位运算符, 相当于 /2, 性能比 /2 稍快if(nums[mid] < target){left = mid + 1;}else if (nums[mid] > target){right = mid - 1;}else if(nums[mid] == target) {//由于是查找右边界, 所以查找到于target相等的元素时, 仍需要向右left = mid + 1; // 持续向右 缩短左边界}   }// right 越界判断,,根据具体题目判断.if(left >= nums.length || nums[left] != target){//根据具体题目判断.}
}

3.2 模板三: 二分查找极值点

  • 二分查找还有一种有趣的变体是二分查找极值点,之前我们使用nums[mid]去比较的时候,常常是和给定的目标值target比,或者和左右边界比较,在二分查找极值点的应用中,我们是和相邻元素去比,以完成某种单调性的检测。关于这一点,我们直接来看一个例子就明白了。

  • 这一题的有趣之处在于他要求求一个局部极大值点,并且整个数组不包含重复元素。所以整个数组甚至可以是无序的——你可能很难想象我们可以在一个无序的数组中直接使用二分查找,但是没错!我们确实可以这么干!谁要人家只要一个局部极大值即可呢。
  • 题解: lt.162- 寻找峰值

4. 总结

  • 参考文章:
  • 二分查找、二分边界查找算法的模板代码总结
  • 对上文的补充

tag数组-刷题预备知识-4.一通百通解决二分查找问题相关推荐

  1. LeetCode:数组刷题(17道经典题目)

    LeetCode 数组刷题(17道经典题目) 本文带来的是以数组为主题的经典题目,主要实现是C++,部分题目也用Python实现了. 704. 二分查找 35.搜索插入位置 34. 在排序数组中查找元 ...

  2. 【代码随想录】数组刷题

    数组刷题 二分 二分查找* 搜索插入位置 在排序数组中查找元素的第一个和最后一个位置* x 的平方根 有效的完全平方数 双指针 移除元素 删除排序数组中的重复项 移动零 比较含退格的字符串 有序数组的 ...

  3. LeetCode 2040. 两个有序数组的第 K 小乘积(嵌套二分查找)

    文章目录 1. 题目 2. 解题 1. 题目 给你两个 从小到大排好序 且下标从 0 开始的整数数组 nums1 和 nums2 以及一个整数 k ,请你返回第 k (从 1 开始编号)小的 nums ...

  4. LeetCode 1940. 排序数组之间的最长公共子序列(二分查找)

    文章目录 1. 题目 2. 解题 1. 题目 给定一个由整数数组组成的数组arrays,其中arrays[i]是严格递增排序的,返回一个表示所有数组之间的最长公共子序列的整数数组. 子序列是从另一个序 ...

  5. LeetCode 540. 有序数组中的单一元素(位运算二分查找)

    1. 题目 给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数. 示例 1: 输入: [1,1,2,3,3,4,4,8,8] 输出: 2示例 2: 输入: [3,3 ...

  6. OJ 刷题必备知识总结(一)

    前言:本篇博客内容总结自<算法笔记>.文章篇幅太长了,更多的内容请读者点击这一篇:PTA 算法笔记重点总结(二). 文章目录 1 int 与 long long 2 字符常量 3 最大整数 ...

  7. 蓝桥杯刷题015——最少刷题数(二分法+前缀和)

    问题描述 小蓝老师教的编程课有 N 名学生, 编号依次是 1-N .第 i 号学生这学期刷题的数量是 Ai​ . 对于每一名学生, 请你计算他至少还要再刷多少道题, 才能使得全班刷题比他多的学生数不超 ...

  8. Leetcode按Tag刷题

    按照Leetcode的Tag来刷题,从easy到hard刷题 关于如何让Leetcode按难易程度排序,可按以下步骤: 1. 进入Leetcode后,点击code 2.点击code后,可查看所有题目, ...

  9. leetcode刷题:求旋转有序数组的最小值

    题目: 分析:由题中所给的描述,不管数组如何旋转,我们的整个数组,其实总是真正有序的适用于二分查找法. 代码如下: #include <stdio.h> int findMin(int* ...

最新文章

  1. Datawhale 内推 | 头条、百度、网易、滴滴、联想、商汤、平安科技等
  2. 线程同步锁 java_java多线程同步之重入锁,详细解析
  3. iOS夯实:RunLoop
  4. 【转】JAVA 并发性和多线程 -- 读感 (二 线程间通讯,共享内存的机制)
  5. Selenium简介以及selenium环境搭建
  6. windows安装nvm
  7. Postman----Presets(预先设置)的使用
  8. redis 缓存预热_Redis常见问题总结
  9. 使用cos组建上传文件
  10. 支持向量机_支持向量机(SVM)说明及示例
  11. MySQL查询指定数据库中所有记录不为空的表
  12. 【2022年江西省研究生数学建模】水汽过饱和的核化除霾 31页论文分析
  13. Cisco思科交换机路由器命令快速入门
  14. listbox tkinter 多选_TKINTER教程之LISTBOX篇
  15. C/C++中最快、最简洁的read()快读(卡常数)方法
  16. 通过蓝牙连接进行ActiveSync同步
  17. 22-02-08数据库迁移sql问题
  18. 破解验证码(2)滑动验证码
  19. 我的Photoshop大师之路(三)
  20. 有谁还在说入门大数据难?从spark开始带你起飞

热门文章

  1. 买了个云服务器怎么使用?只需三步骤就可以建站
  2. Swift 小仿微博列表
  3. Vikki与您共享系列五:最适合威客阅读的书籍
  4. mysql 反向匹配子串,Mysql 模糊匹配(字符串str中是否包含子字符串substr)
  5. linux中软链接和硬链接,Linux中软链接和硬链接的区别
  6. 小鑫吃苹果 3105
  7. axios是什么?如何在项目中使用?
  8. 超低成本DDoS攻击来袭,看WAF如何绝地防护
  9. Java的万能进制转换
  10. 伪随机序列的产生c语言,伪随机序列的c语言编程实现.pdf