tag数组-刷题预备知识-4.一通百通解决二分查找问题
文章目录
- 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. 二分查找的几个模版
一般而言,当一个题目出现以下特征之一时, 我们应该联想到它是否能够使用二分查找解题:
- 待查找的数组有序或局部有序
- 题目要求我们解题的时间复杂度低于 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.一通百通解决二分查找问题相关推荐
- LeetCode:数组刷题(17道经典题目)
LeetCode 数组刷题(17道经典题目) 本文带来的是以数组为主题的经典题目,主要实现是C++,部分题目也用Python实现了. 704. 二分查找 35.搜索插入位置 34. 在排序数组中查找元 ...
- 【代码随想录】数组刷题
数组刷题 二分 二分查找* 搜索插入位置 在排序数组中查找元素的第一个和最后一个位置* x 的平方根 有效的完全平方数 双指针 移除元素 删除排序数组中的重复项 移动零 比较含退格的字符串 有序数组的 ...
- LeetCode 2040. 两个有序数组的第 K 小乘积(嵌套二分查找)
文章目录 1. 题目 2. 解题 1. 题目 给你两个 从小到大排好序 且下标从 0 开始的整数数组 nums1 和 nums2 以及一个整数 k ,请你返回第 k (从 1 开始编号)小的 nums ...
- LeetCode 1940. 排序数组之间的最长公共子序列(二分查找)
文章目录 1. 题目 2. 解题 1. 题目 给定一个由整数数组组成的数组arrays,其中arrays[i]是严格递增排序的,返回一个表示所有数组之间的最长公共子序列的整数数组. 子序列是从另一个序 ...
- LeetCode 540. 有序数组中的单一元素(位运算二分查找)
1. 题目 给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数. 示例 1: 输入: [1,1,2,3,3,4,4,8,8] 输出: 2示例 2: 输入: [3,3 ...
- OJ 刷题必备知识总结(一)
前言:本篇博客内容总结自<算法笔记>.文章篇幅太长了,更多的内容请读者点击这一篇:PTA 算法笔记重点总结(二). 文章目录 1 int 与 long long 2 字符常量 3 最大整数 ...
- 蓝桥杯刷题015——最少刷题数(二分法+前缀和)
问题描述 小蓝老师教的编程课有 N 名学生, 编号依次是 1-N .第 i 号学生这学期刷题的数量是 Ai . 对于每一名学生, 请你计算他至少还要再刷多少道题, 才能使得全班刷题比他多的学生数不超 ...
- Leetcode按Tag刷题
按照Leetcode的Tag来刷题,从easy到hard刷题 关于如何让Leetcode按难易程度排序,可按以下步骤: 1. 进入Leetcode后,点击code 2.点击code后,可查看所有题目, ...
- leetcode刷题:求旋转有序数组的最小值
题目: 分析:由题中所给的描述,不管数组如何旋转,我们的整个数组,其实总是真正有序的适用于二分查找法. 代码如下: #include <stdio.h> int findMin(int* ...
最新文章
- Datawhale 内推 | 头条、百度、网易、滴滴、联想、商汤、平安科技等
- 线程同步锁 java_java多线程同步之重入锁,详细解析
- iOS夯实:RunLoop
- 【转】JAVA 并发性和多线程 -- 读感 (二 线程间通讯,共享内存的机制)
- Selenium简介以及selenium环境搭建
- windows安装nvm
- Postman----Presets(预先设置)的使用
- redis 缓存预热_Redis常见问题总结
- 使用cos组建上传文件
- 支持向量机_支持向量机(SVM)说明及示例
- MySQL查询指定数据库中所有记录不为空的表
- 【2022年江西省研究生数学建模】水汽过饱和的核化除霾 31页论文分析
- Cisco思科交换机路由器命令快速入门
- listbox tkinter 多选_TKINTER教程之LISTBOX篇
- C/C++中最快、最简洁的read()快读(卡常数)方法
- 通过蓝牙连接进行ActiveSync同步
- 22-02-08数据库迁移sql问题
- 破解验证码(2)滑动验证码
- 我的Photoshop大师之路(三)
- 有谁还在说入门大数据难?从spark开始带你起飞