二分查找算法
1 Java算法篇之二分查找算法
1.1 什么是二分查找算法?
- 算法定义
二分查找算法又叫折半查找算法, 是一种基于比较目标值和数组中间元素的教科书式算
- 使用条件
待查找的数组必须是有顺序的
- 复杂度
空间复杂度:O(1)
- 时间复杂度最好情况:O(1)
- 时间复杂度最坏情况:O(LogN) 一般默认指这种。
注意:
可能也听过下面这种说法:
它们两个其实是等价的,log2n 的意思是以2为底数,然后n.
- 算法规则
- 如果目标值等于中间元素,则找到目标值。
- 如果目标值较小,继续在左侧搜索。
- 如果目标值较大,则继续在右侧搜索。
1.2 二分查找算法分析
LeetCode最佳算法解析,请移步二分查找细节详解,顺便赋诗一首
- 初始化指针 left = 0, right = n - 1。
- 当 left <= right:
- 比较中间元素 nums[pivot] 和目标值 target 。
- 如果 target = nums[pivot],返回 pivot。
- 如果 target < nums[pivot],则在左侧继续搜索 right = pivot - 1。
- 如果 target > nums[pivot],则在右侧继续搜索 left = pivot + 1。
1.3 Solution
1.3.1 LeetCode 官方解法
LeetCode 官方二分法解法
class Solution {
public int search(int[] nums, int target) {
int pivot, left = 0, right = nums.length - 1;
while (left <= right) {
pivot = left + (right - left) / 2;
if (nums[pivot] == target) return pivot;
if (target < nums[pivot]) right = pivot - 1;
else left = pivot + 1;
}
return -1;
}
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/binary-search/solution/er-fen-cha-zhao-by-leetcode/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1.3.2 最佳二分法查找Solution
给大家讲个笑话乐呵一下:
- 有一天阿东到图书馆借了 N本书,出图书馆的时候,警报响了,于是保安把阿东拦下,要检查一下哪本书没有登记出借。阿东正准备把每一本书在报警器下过一下,以找出引发警报的书,但是保安露出不屑的眼神:你连二分查找都不会吗?于是保安把书分成两堆,让第一堆过一下报警器,报警器响;于是再把这堆书分成两堆……
- 最终,检测了 logN 次之后,保安成功的找到了那本引起警报的书,露出了得意和嘲讽的笑容。于是阿东背着剩下的书走了。
- 从此,图书馆丢了 N - 1 本书。
事故现场还原:
数组下标:0 1 2 3 4
存储内容:1 2 2 2 3
比如说给你有序数组 nums = [1,2,2,2,3],target 为 2,上面算法返回的索引是 2,没错。但是如果我想得到 target 的左侧边界,即索引 1,或者我想得到 target 的右侧边界,即索引 3,这样的话此算法是无法处理的。
解决上述需求,完整算法如下:
保安用的基础二分法算法如下:
//和官方的Leetcode 算法一致
//基础二分查找算法
int binary_search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
// 搜索区间变为 [mid+1, right]
left = mid + 1;
} else if (nums[mid] > target) {
// 搜索区间变为 [left, mid-1]
right = mid - 1;
} else if(nums[mid] == target) {
// 直接返回
return mid;
}
}
// 直接返回
return -1;
}
左侧边界二分法算法如下:
//左侧边界查找算法
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,收缩左侧边界
right = mid - 1;
}
}
// 最后要检查 left 越界的情况
if (left >= nums.length || nums[left] != target){
return -1;
}
return left;
}
右侧边界二分法算法如下:
//右侧边界查询算法
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,收缩右侧边界
left = mid + 1;
}
}
// 最后要检查 right 越界的情况
if (right < 0 || nums[right] != target){
return -1;
}
return right;
}
作者:labuladong
链接:https://leetcode-cn.com/problems/binary-search/solution/er-fen-cha-zhao-xiang-jie-by-labuladong/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
更多学习资源:https://github.com/labuladong/fucking-algorithm
本篇完~