首页 > 其他分享 >二分查找总结

二分查找总结

时间:2022-11-25 11:39:35浏览次数:48  
标签:二分 总结 right target nums int mid 查找 left

二分查找

二分查找也常被称为二分法或者折半查找(Binary Search),每次查找时通过将待查找区间分成两部分并只取一部分继续查找,将查找的复杂度大大减少。对于一个长度为 O(n) 的数组,二分查找的时间复杂度为 O(log n)。二分查找也可以看作双指针的一种特殊情况。双指针类型指针通常是一步一步移动的,而在二分查找里指针每次移动半个区间长度。通常题目给定顺序存储结构我们可以联想到二分查找。

下面给出了二分查找的算法框架,需要注意的部分就在于左右边界的初始定义、while循环执行的条件以及判断后左右边界如何移动。


二分查找算法框架

public int binarySearch(int[] nums, int target) {
// 定义左右边界
int left = 0, right = ...;
// 遍历
while(...) {
// 取区间中点位置 使用 left + (right - left) / 2 比使用 (left + right) / 2 更好,可以避免溢出
int mid = left + (right - left) / 2;
// 如果找到目标值,则执行...
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
// 如果中点值小于目标值,则缩小区间,移动左边界
left = ...
} else if (nums[mid] > target) {
// 如果中点值大于目标值,则缩小区间,移动右边界
right = ...
}
}
// 返回值
return ...;
}


二分查找一个数的算法框架

// 搜索区间:左闭右闭区间
public int binarySearch(int[] nums, int target) {
// 定义左边界为数组头
int left = 0;
// 定义右边界为数组长度减一
int right = nums.length - 1;
// 当左边界小于等于右边界时执行循环 左闭右闭区间 [left, right]
while(left <= right) {
// 获取区间中点位置
int mid = left + (right - left) / 2;
// 如果中点值等于目标值,返回查找到该目标元素的位置
if(nums[mid] == target)
return mid;
// 如果中点值小于目标值,则缩小区间至右子区间,左边界位置移动到中点下一个位置
else if (nums[mid] < target)
left = mid + 1;
// 如果中点值大于目标值,则缩小区间至左子区间,右边界位置移动到中点前一个位置
else if (nums[mid] > target)
right = mid - 1;
}
// 找不到目标值,返回-1
return -1;
}


寻找左侧边界的二分查找算法框架

// 搜索区间:左闭右开区间
public int left_bound(int[] nums, int target) {
// 如果数组为空,直接返回-1
if (nums.length == 0)
return -1;
// 定义左边界起始为0
int left = 0;
// 定义右边界起始为数组长度
int right = nums.length;
// 当左边界小于右边界时执行循环 搜索区间是 [left, right) 左闭右开
while (left < right) {
// 获取中点位置
int mid = (left + right) / 2;
// 如果中点值等于目标值,右边界更新为中点位置
if (nums[mid] == target)
right = mid;
// 如果中点值小于目标值,左边界更新为中点下一个位置
else if (nums[mid] < target)
left = mid + 1;
// 如果中点值大于目标值,右边界更新为中点位置
else if (nums[mid] > target)
right = mid;
}
// target 比所有数都大,返回-1
if (left == nums.length)
return -1;
// 如果左边界值等于目标值则返回左边界位置,否则返回-1
return nums[left] == target ? left : -1;
}


寻找右侧边界的二分查找算法框架

// 搜索区间:左闭右开区间
public int right_bound(int[] nums, int target) {
// 如果数组为空,直接返回-1
if (nums.length == 0)
return -1;
// 定义左边界起始为0
int left = 0;
// 定义右边界起始为数组长度
int right = nums.length;
// 当左边界小于右边界时执行循环
while (left < right) {
// 获取中点位置
int mid = (left + right) / 2;
// 如果中点值等于目标值,左边界更新为中点下一个位置
if (nums[mid] == target)
left = mid + 1;
// 如果中点值小于目标值,左边界更新为中点下一个位置
else if (nums[mid] < target)
left = mid + 1;
// 如果中点值大于目标值,右边界更新为中点位置
else if (nums[mid] > target)
right = mid;
}
// 左边界还在初始位置,返回-1
if (left == 0)
return -1;
// 如果左边界左边一个元素值等于目标值则返回左边界左边一个元素的位置,否则返回-1
return nums[left - 1] == target ? (left-1) : -1;
}


以上三种框架的左闭右闭区间算法

// 二分查找一个数的算法框架
public 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) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if(nums[mid] == target) {
// 直接返回
return mid;
}
}
// 直接返回
return -1;
}


// 寻找左侧边界的二分查找算法框架
public 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;
}


// 寻找右侧边界的二分查找算法框架
public 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;
}



标签:二分,总结,right,target,nums,int,mid,查找,left
From: https://blog.51cto.com/u_15891283/5886054

相关文章

  • LeetCode 34.在排序数组中查找元素的第一个和最后一个位置
    LeetCode34.在排序数组中查找元素的第一个和最后一个位置题目链接:​​https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/​​......
  • LOJ #6044 题解——完全二分图的生成树计数
    LOJ#6044显然就是要求有多少左边有\(K\)个点,右边有\(N-K\)个点的完全二分图的生成树个数,但是我不会!所以我们想一想怎么算左边\(n\)个点,右边\(m\)个点的完全二分......
  • 每日算法之二维数组中的查找
    JZ4二维数组中的查找描述在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这......
  • Java对象值传递和对象传递的总结
    值传递和对象传递的问题总结下。   先看基本类型作为参数传递的例子:publicclassTest1{publicstaticvoidmain(String[]args){intn=3;System.......
  • 第九章运行存储分配常考大题总结(二)一些题
    题一 解题思路:先画出整体的活动树 (1)题干指出当前执行过程为quicksort(2,3),意为q(5,9)一侧不需要考虑,因为q(1,3)先执行完才能执行q(5,9),本题轮不到q(5,9)main()-......
  • Oracle中字符串截取最全方法总结
    substr函数:截取字符串语法:SUBSTR(string,start, [length])string:表示源字符串,即要截取的字符串。start:开始位置,从1开始查找。如果start是负数,则从string字符串末......
  • java23种设计模式概述总结
    软件设计模式的意义:它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠......
  • Docker总结整合(一)
    1、简介Docker是一个开源的应用容器引擎;是一个轻量级容器技术;Docker支持将软件编译成一个镜像;然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使用这个镜像......
  • 总结Vue父子组件相互传值和路由传值的两种方式【后续更新】
    1、父到子思路总结:   1、定义子组件接收父组件的变量在props['child'],的单独的属性中,与data()平行;   2、在父组件中给子组件中定义的变量赋值==> :child="pare......
  • Flink与Hive集成错误总结
    1.Causedby:java.lang.ClassNotFoundException:org.apache.hive.common.util.HiveVersionInfo原因:flink缺少hive-exec-3.1.2.jar包解决方法:cp/usr/local/hive/lib/......