LeetCode——二分查找
二分查找
目录
- 二分查找法
- 求开方
- 大于给定元素的最小元素
- 有序数组的 Single Element
- 第一个错误的版本
- 旋转数组的最小数字
- 查找区间
1. 二分查找法
正常实现
public int binarySearch(int[] nums, int key) {int l = 0, h = nums.length - 1;while (l <= h) {int m = l + (h - l) / 2;if (nums[m] == key) {return m;} else if (nums[m] > key) {h = m - 1;} else {l = m + 1;}}return -1;}
时间复杂度
二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度为 O(logN)。
m 计算
有两种计算中值 m 的方式:
- m = (l + h) / 2
- m = l + (h - l) / 2l + h 可能出现加法溢出,也就是说加法的结果大于整型能够表示的范围。但是 l 和 h 都为正数,因此 h - l 不会出现
加法溢出问题。所以,最好使用第二种计算法方法。
未成功查找的返回值
循环退出时如果仍然没有查找到 key,那么表示查找失败。可以有两种返回值:
- -1:以一个错误码表示没有查找到 key
- l:将 key 插入到 nums 中的正确位置
变种
二分查找可以有很多变种,变种实现要注意边界值的判断。例如在一个有重复元素的数组中查找 key 的最左位置的实现如下:
public int binarySearch2(int[] nums, int key) {int l = 0, h = nums.length - 1;while (l < h) {int m = l + (h - l) / 2;if (nums[m] >= key) {h = m ;} else {l = m + 1;}}return l;}
该实现和正常实现有以下不同:
- h 的赋值表达式为 h = m
- 循环条件为 l < h
- 最后返回 l 而不是 -1
在 nums[m] >= key 的情况下,可以推导出最左 key 位于 [l, m] 区间中,这是一个闭区间。h 的赋值表达式为 h =m,因为 m 位置也可能是解。
在 h 的赋值表达式为 h = m 的情况下,如果循环条件为 l <= h,那么会出现循环无法退出的情况,因此循环条件只能是 l < h。以下演示了循环条件为 l <= h 时循环无法退出的情况
当循环体退出时,不表示没有查找到 key,因此最后返回的结果不应该为 -1。为了验证有没有查找到,需要在调用端判断一下返回位置上的值和 key 是否相等。
2. 求开方
public int mySqrt(int x) {if (x <= 1) {return x;}int l = 1;int h = x;while (l <= h) {int mid = l + (h - l) / 2;int sqrt = x / mid;if (mid == sqrt) {return sqrt;} else if (mid > sqrt) {h = mid - 1;} else {l = mid + 1;}}return h;}
3. 大于给定元素的最小元素
题目描述:给定一个有序的字符数组 letters 和一个字符 target,要求找出 letters 中大于 target 的最小字符,如果找不到就返回第 1 个字符。
public char nextGreatestLetter(char[] letters, char target) {int n = letters.length;int l = 0, h = n - 1;while (l <= h) {int m = l + (h - l) / 2;if (letters[m] >= target) {h = m - 1;} else {l = m + 1;}}return l < n ? letters[l] : letters[0];}
4. 有序数组的 Single Element
题目描述:一个有序数组只有一个数不出现两次,找出这个数。
要求以 O(logN) 时间复杂度进行求解,因此不能遍历数组并进行异或操作来求解,这么做的时间复杂度为 O(N)。
令 index 为 Single Element 在数组中的位置。在 index 之后,数组中原来存在的成对状态被改变。如果 m 为偶数,并且 m + 1 < index,那么 nums[m] == nums[m + 1];m + 1 >= index,那么 nums[m] != nums[m + 1]。
从上面的规律可以知道,如果 nums[m] == nums[m + 1],那么 index 所在的数组位置为 [m + 2, h],此时令 l = m +2;如果 nums[m] != nums[m + 1],那么 index 所在的数组位置为 [l, m],此时令 h = m。
因为 h 的赋值表达式为 h = m,那么循环条件也就只能使用 l < h 这种形式
public int singleNonDuplicate(int[] nums) {int l = 0;int h = nums.length - 1;while (l < h) {int m = l + (h - l) / 2;while (m % 2 == 1) {m--; // 保证 l/h/m 都在偶数位,使得查找区间大小一直都是奇数}if (nums[m] == nums[m + 1]) {l = m + 2;} else {h = m;}}return nums[l];}
5. 第一个错误的版本
题目描述:给定一个元素 n 代表有 [1, 2, …, n] 版本,在第 x 位置开始出现错误版本,导致后面的版本都错误。可以调用 isBadVersion(int x) 知道某个版本是否错误,要求找到第一个错误的版本。
如果第 m 个版本出错,则表示第一个错误的版本在 [l, m] 之间,令 h = m;否则第一个错误的版本在 [m + 1, h] 之间,令 l = m + 1。
因为 h 的赋值表达式为 h = m,因此循环条件为 l < h。
public int firstBadVersion(int n) {int l = 1, h = n;while (l < h) {int mid = l + (h - l) / 2;if (isBadVersion(mid)) {h = mid;} else {l = mid + 1;}}return l;}
6. 旋转数组的最小数字
public int findMin(int[] nums) {int l = 0, h = nums.length - 1;while (l < h) {int m = l + (h - l) / 2;if (nums[m] <= nums[h]) {h = m;} else {l = m + 1;}}return nums[l];}
7. 查找区间
public int[] searchRange(int[] nums, int target) {int first = binarySearch(nums, target);int last = binarySearch(nums, target + 1) - 1;if (first == nums.length || nums[first] != target) {return new int[]{-1, -1};} else {return new int[]{first, Math.max(first, last)};}}private int binarySearch(int[] nums, int key) {int l = 0, h = nums.length - 1;while (l < h) {int m = l + (h - l) / 2;if (nums[m] >= key) {h = m;} else {l = m + 1;}}return l;}
LeetCode——二分查找相关推荐
- 七十六、Python | Leetcode二分查找和分治算法系列
@Author:Runsen @Date:2020/7/4 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...
- LeetCode 二分查找
文章目录 [0378. 有序矩阵中第K小的元素 [Medium] [Kth Smallest Element in a Sorted Matrix]](https://leetcode.com/pro ...
- 【LeetCode 二分查找专项】最长递增子序列(300)(to be polished...)
文章目录 1. 题目 1.1 示例 1.2 说明 1.3 提示 1.4 进阶 2. 解法一(动态规划) 2.1 分析 2.2 解答 2.3 复杂度 3. 解法二(二分查找) 3.1 分析 3.2 解答 ...
- leetcode 二分查找 Search in Rotated Sorted ArrayII
Search in Rotated Sorted Array II Total Accepted: 18500 Total Submissions: 59945My Submissions Follo ...
- leetcode二分查找
1.猜数字进行二分查找: 2.查找两个数组之间的重复交叉项 转载于:https://www.cnblogs.com/mmziscoming/p/5777008.html
- LeetCode二分查找问题全集
文章目录 二分查找框架 704. 二分查找 33. 搜索旋转排序数组 81. 搜索旋转排序数组 II 153. 寻找旋转排序数组中的最小值 154. 寻找旋转排序数组中的最小值 II 300. 最长上 ...
- [LeetCode]704.二分查找及相关题目
数组理论基础 数组理论 数组是存放在连续内存空间上的相同类型数据的集合 数组可以方便的通过下标索引的方式获取到下标下对应的数据 二维数组在内存的空间地址是连续的 二分查找 LeetCode 704.二 ...
- LeetCode简单题之二分查找
题目 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1. 示例 1: 输入: n ...
- 「二分查找」之我见!今天刷一道leetcode算法!
来自:码农田小齐 算法将是我今后更新的重点,因为我个人非常喜欢..而且面试考它啊!有人说刷题没有用,但是你做了题就能感受到 coding 能力的提升和对语言熟悉度的提升.新的一年,每日一题,我们一起进 ...
最新文章
- .NET Framework 4.7 安装
- java中volatile的含义_java中volatile关键字的含义
- C#-ToString格式化
- Simulink之单管非隔离直流斩波器
- Centos6.6安装Nginx
- shell脚本连接、读写、操作mysql数据库实例
- paip.PHP代码生成器比较
- 肌电信号分析相关链接分享
- QQ游戏大厅的你画我猜游戏白屏问题解决
- python 菜鸟教程 xml-【读书】Django教程(菜鸟教程)
- MATLAB自带插值函数
- ArcGIS中ObjectID,FID和OID字段区别
- 使用记事本完成第一个Java程序的开发遇到异常
- POJ 1118 Lining Up 叉积,三点共线。
- html制作网站 知乎,做短视频运营看那些网站(推荐这些短视频素材网站)
- 代理IP如何解决爬虫IP被封
- 【c语言作业-二维数组】编写程序,求一个给定的n阶方阵的鞍点。
- 2023年Mathorcup高校数学建模挑战赛ABCD题思路资料汇总贴
- java计算机毕业设计三坑购物平台演示录像2020源代码+数据库+系统+lw文档
- python等差数列求和公式前 100 项的和
热门文章
- 自己动手写一个 SimpleVue
- 理解C#语言中的类型转换----初学者的理解,请大神指教
- 新页面,简单的tree视图写法
- gparted在线扩分区大小
- GIT入门笔记(5)- 创建版本库
- 37. C# -- 装箱和拆箱
- 假如谷歌真的和ICQ一起了
- C++debug调试出现heap corruption detected: after normal block 可能的原因
- CodeForces - 504B Misha and Permutations Summation(线段树模拟康托展开与逆展开)
- php tp框架调用方法,thinkPHP框架使用方法