转载自:https://www.cnblogs.com/luoxn28/p/5767571.html

1 二分查找

  二分查找是一个基础的算法,也是面试中常考的一个知识点。二分查找就是将查找的键和子数组的中间键作比较,如果被查找的键小于中间键,就在左子数组继续查找;如果大于中间键,就在右子数组中查找,否则中间键就是要找的元素。

(图片来自《算法-第4版》)

/**
* 二分查找,找到该值在数组中的下标,否则为-1
*/
static int binarySerach(int[] array, int key) {
int left = 0;
int right = array.length - 1; // 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] == key) {
return mid;
}
else if (array[mid] < key) {
left = mid + 1;
}
else {
right = mid - 1;
}
} return -1;
}

  每次移动left和right指针的时候,需要在mid的基础上+1或者-1, 防止出现死循环, 程序也就能够正确的运行。

  注意:代码中的判断条件必须是while (left <= right),否则的话判断条件不完整,比如:array[3] = {1, 3, 5};待查找的键为5,此时在(low < high)条件下就会找不到,因为low和high相等时,指向元素5,但是此时条件不成立,没有进入while()中。

2 二分查找的变种

  关于二分查找,如果条件稍微变换一下,比如:数组之中的数据可能可以重复,要求返回匹配的数据的最小(或最大)的下标;更近一步, 需要找出数组中第一个大于key的元素(也就是最小的大于key的元素的)下标,等等。 这些,虽然只有一点点的变化,实现的时候确实要更加的细心。

  二分查找的变种和二分查找原理一样,主要就是变换判断条件(也就是边界条件),如果想直接看如何记忆这些变种的窍门,请直接翻到本文最后。下面来看几种二分查找变种的代码:

2.1 查找第一个与key相等的元素

  查找第一个相等的元素,也就是说等于查找key值的元素有好多个,返回这些元素最左边的元素下标。

// 查找第一个相等的元素
static int findFirstEqual(int[] array, int key) {
int left = 0;
int right = array.length - 1; // 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] >= key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
if (left < array.length && array[left] == key) {
return left;
} return -1;
}

2.2 查找最后一个与key相等的元素

  查找最后一个相等的元素,也就是说等于查找key值的元素有好多个,返回这些元素最右边的元素下标。

// 查找最后一个相等的元素
static int findLastEqual(int[] array, int key) {
int left = 0;
int right = array.length - 1; // 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] <= key) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
if (right >= 0 && array[right] == key) {
return right;
} return -1;
}

2.3 查找最后一个等于或者小于key的元素

  查找最后一个等于或者小于key的元素,也就是说等于查找key值的元素有好多个,返回这些元素最右边的元素下标;如果没有等于key值的元素,则返回小于key的最右边元素下标。

// 查找最后一个等于或者小于key的元素
static int findLastEqualSmaller(int[] array, int key) {
int left = 0;
int right = array.length - 1; // 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] > key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return right;
}

2.4 查找最后一个小于key的元素

  查找最后一个小于key的元素,也就是说返回小于key的最右边元素下标。

// 查找最后一个小于key的元素
static int findLastSmaller(int[] array, int key) {
int left = 0;
int right = array.length - 1; // 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] >= key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return right;
}

2.5 查找第一个等于或者大于key的元素

  查找第一个等于或者大于key的元素,也就是说等于查找key值的元素有好多个,返回这些元素最左边的元素下标;如果没有等于key值的元素,则返回大于key的最左边元素下标。

// 查找第一个等于或者大于key的元素
static int findFirstEqualLarger(int[] array, int key) {
int left = 0;
int right = array.length - 1; // 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] >= key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return left;
}

2.6 查找第一个大于key的元素

  查找第一个等于key的元素,也就是说返回大于key的最左边元素下标。

// 查找第一个大于key的元素
static int findFirstLarger(int[] array, int key) {
int left = 0;
int right = array.length - 1; // 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] > key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return left;
}

3 二分查找变种总结

// 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] ? key) {
//... right = mid - 1;
}
else {
// ... left = mid + 1;
}
}
return xxx;

  二分查找变种较多,不过它们的“套路”是一样的,以上代码就是其套路,如何快速写出二分查找的代码,只需按照以下步骤即可:

1 首先判断出是返回left,还是返回right

  因为我们知道最后跳出while (left <= right)循环条件是right < left,且right = left - 1。最后right和left一定是卡在"边界值"的左右两边,如果是比较值为key,查找小于等于(或者是小于)key的元素,则边界值就是等于key的所有元素的最左边那个,其实应该返回left。

  以数组{1, 2, 3, 3, 4, 5}为例,如果需要查找第一个等于或者小于3的元素下标,我们比较的key值是3,则最后left和right需要满足以下条件:

  我们比较的key值是3,所以此时我们需要返回left。

2 判断出比较符号

int mid = (left + right) / 2;
if (array[mid] ? key) {
//... right = xxx;
}
else {
// ... left = xxx;
}

  也就是这里的 if (array[mid] ? key) 中的判断符号,结合步骤1和给出的条件,如果是查找小于等于key的元素,则知道应该使用判断符号>=,因为是要返回left,所以如果array[mid]等于或者大于key,就应该使用>=,以下是完整代码

// 查找小于等于key的元素
int mid = (left + right) / 2;
if (array[mid] >= key) {
right = mid - 1;
}
else {
left = mid + 1;
}

二分查找(lower_bound和upper_bound)的更多相关文章

  1. STL中的二分查找——lower_bound 、upper_bound 、binary_search

    STL中的二分查找函数 1.lower_bound函数 在一个非递减序列的前闭后开区间[first,last)中.进行二分查找查找某一元素val.函数lower_bound()返回大于或等于val的第 ...

  2. LeetCode:Search Insert Position,Search for a Range (二分查找,lower_bound,upper_bound)

    Search Insert Position Given a sorted array and a target value, return the index if the target is fo ...

  3. STL中的二分查找———lower_bound,upper_bound,binary_search

    关于STL中的排序和检索,排序一般用sort函数即可,今天来整理一下检索中常用的函数——lower_bound , upper_bound 和 binary_search . STL中关于二分查找的函 ...

  4. Long Jumps(二分查找lower_bound()函数的运用)

    Valery is a PE teacher at a school in Berland. Soon the students are going to take a test in long ju ...

  5. HDU 5178:pairs(二分,lower_bound和upper_bound)

    pairs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  6. 线段树离散化 unique + 二分查找 模板 (转载)

    离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率. 通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小.例如: 原数据:1,999,100000,15:处理 ...

  7. 徒手实现lower_bound和upper_bound

    STL中lower_bound和upper_bound的使用方法:STL 二分查找 lower_bound: ; ; //初始化 l ,为第一个合法地址 ; //初始化 r , 地址的结束地址 int ...

  8. 分治算法(二分查找)、STL函数库的应用第五弹——二分函数

    分治算法:二分查找!昨天刚说不写算法了,但是突然想起来没写过分治算法的博客,所以强迫症的我…… STL函数库第五弹——二分函数lower_bound().upper_bound().binary_se ...

  9. STL 二分查找三兄弟(lower_bound(),upper_bound(),binary_search())

    一:起因 (1)STL中关于二分查找的函数有三个:lower_bound .upper_bound .binary_search  -- 这三个函数都运用于有序区间(当然这也是运用二分查找的前提),以 ...

  10. 二分查找法(binary_search,lower_bound,upper_bound,equal_range)

    binary_search(二分查找) //版本一:调用operator<进行比较 template <class ForwardIterator,class StrictWeaklyCo ...

随机推荐

  1. android-------开发常用框架汇总

    响应式编程 RxJava https://github.com/ReactiveX/RxJava RxAndroid https://github.com/ReactiveX/RxAndroid 消息 ...

  2. 电脑用U盘启动

    除了根据提示按DEL或者F2进入到BIOS界面更改设置之外. 还可以在开机时按F8或F12进入到引导界面,可直接选择USB. 当把登录用户登录,其他用户都被禁用时,电脑登不进去.要制作启动U盘,进入到 ...

  3. PHP字符串函数小结

    1. strlen:获得字符串长度 2. substr:字符串截取函数 格式:string substr ( string $string , int $start [, int $length ] ...

  4. 『PyTorch』第四弹_通过LeNet初识pytorch神经网络_上

    总结一下相关概念: torch.Tensor - 一个近似多维数组的数据结构 autograd.Variable - 改变Tensor并且记录下来操作的历史记录.和Tensor拥有相同的API,以及b ...

  5. 论raw_input与input之间的缠缠绵绵

    例子1:py2.7中,raw_input输入整数,返回的是str. input1=raw_input("raw_input:") print(type(input1)) print ...

  6. 【MySQL】【4】数据库时间与实际时间相差8小时

    原因:由于默认的是UTC时间,所以在中国有8个小时的时差,需要将serverTimezone的值改为GMT%2B8 spring: datasource: url: jdbc:mysql://172. ...

  7. Centos7 JDK安装过程中 解决java -version 报错: bash: /home/jdk1.8.0_161/bin/java: Permission denied

    1.执行Linux命令 -----vim /etc/profile  编辑profile  文件,在里面添加: #set java enviroment JAVA_HOME=/opt/JavaHome ...

  8. UI基础三:简单的BOL报表开发

    巧了...刚好一个需求,就直接来撸起来吧. 需要做一个报表: 1.创建查询结构和结果结构 2.创建实施类: SE24创建ZCL_JPEXPORT_ORDER_IL 更改父类:CL_WCF_GENIL_ ...

  9. Grafana安装配置介绍

    一.Grafana介绍 Grafana是一个可视化面板(Dashboard),有着非常漂亮的图表和布局展示,功能齐全的度量仪表盘和图形编辑器,支持Graphite.zabbix.InfluxDB.Pr ...

  10. vue element-ui 通过v-for渲染的el-form-item组件,使用自带的表单验证

    HTML: <el-form ref="newTermDetail" :model="newTermDetail" class="auto_fo ...