模板:(通用模板,推荐)

  给定一个排序的整数数组(升序)和一个要查找的整数target,用O(logn)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1

int binarySearch(vector<int> &array, int target) {
if (array.size() == ) {
return -;
} int start = ;
int end = array.size() - ;
int mid; while (start + < end) {
mid = start + (end - start) / ;
if (array[mid] == target) {
end = mid;
} else if (array[mid] < target){
start = mid;
} else if (array[mid] > target) {
end = mid;
}
} if (array[start] == target) {
return start;
} else if (array[end] == target) {
return end;
} return -;
}

  若将条件改为查找target最后一次出现的下标(从0开始),那么程序将发生改变,循环中如果 array[mid] = target, 则 start = mid; 且最后的边界判断改为先判断

array[end] == target; 其他不变。

int binarySearch(vector<int> &array, int target) {
if (array.size() == ) {
return -;
} int start = ;
int end = array.size() - ;
int mid; while (start + < end) {
mid = start + (end - start) / ;
if (array[mid] <= target) {
start = mid;
} else {
end = mid;
}
} if (array[end] == target) {
return end;
}
if (array[start] == target) {
return start;
} return -;
}

解析:

  已排序很重要,而且排序是降序还是升序写法也不一样。

  写程序先写异常处理,这里对应的是数组为空的情况。

  start 和 end 分别初始化为 0 和 array.size() - 1。

  取中值使用 mid = start + (end - start) / 2; 目的是为了防止 start + end 的值超出int范围发生溢出错误。

  循环停止条件为 start < end-1;没有等号,如果取等号,那么有可能进入死循环,如:start = 1; end = 2; 那么 mid = 1;那么此时如果令 start = mid,程序将进入死循环。

  循环停止时肯定有 start + 1 == end;或者数组元素只有一个,也就是说 start 和 end 要么相邻(数组元素个数大于1),要么相交(数组元素个数为1),那么都可以归结为最后的判断语句,根据题目的要求(第一次出现还是最后一次出现)确定判断顺序。 

模板 2:(不推荐)

  模板 1 是start == end - 1 时停止循环,下面给出另一种处理,即 start == end时停止循环。

First pos

int binarySearch(vector<int> &array, int target) {
if (array.size() == ) {
return -;
} int start = ;
int end = array.size() - ;
int mid; while (start < end) {
mid = start + (end - start) / ;
if (array[mid] < target) {
start = mid + ;
} else if (array[mid] > target) {
end = mid - ;
} else {
end = mid;
}
} if (array[end] == target) {
return end;
} return -;
}

Last pos

  按照模板 1 的逻辑,写成下面这样(这是错误的!!!

int binarySearchLast(vector<int> &array, int target) {
if (array.size() == ) {
return -;
} int start = ;
int end = array.size() - ;
int mid; while (start < end) {
mid = start + (end - start) / ;
if (array[mid] < target) {
start = mid + ;
} else if (array[mid] > target) {
end = mid - ;
} else {
start = mid;
}
} if (array[start] == target) {
return start;
} return -;
}

  看上去逻辑好像很对,但是有一个很严重的错误,那就是有可能会进入死循环:如 start 和 end 指向 1 和 1 且 start = end; 那么此时 mid = start;start = end;相当于start 始终不会变,关键就在于循环条件的判断。那么为什么会造成这个原因呢?仔细想一想就会知道,问题出在求 mid 上,对 2 取模, 2 和 3 的结果是一样的,就是说两个数相邻,那么这两个数的“中值”(mid = start + (end - start)/ 2)始终是第一个,如果程序循环中需要移动候选区间,就有可能造成死循环。就像模板2 中求第一个位置就不会发生死循环,因为移动的是end,除非 start = end,否则 end 是 不会等于mid 的,相反,在求最后一个位置是,若循环条件允许start + 1 == end,那么当需要移动 start 时,就有可能遇到 start 一直等于 mid 的情况, 故不推荐此循环判断方案, 采用模板一的方案,在 start + 1 == end时停止循环,然后根据需要决定 start 和 end 的判断顺序 。当然也可以用模板二的循环方案,只是一定要避免发生死循环的情况。

Last pos (正确的解法)

int binarySearchLast(vector<int> &array, int target) {
if (array.size() == ) {
return -;
} int start = ;
int end = array.size() - ;
int mid; while (start < end - ) {
mid = start + (end - start) / ;
if (array[mid] < target) {
start = mid + ;
} else if (array[mid] > target) {
end = mid - ;
} else {
start = mid;
}
} if (array[end] == target) {
return end;
}
if (array[start] == target) {
return start;
} return -;
}

【算法模板】Binary Search 二分查找的更多相关文章

  1. [01]Binary Search二分查找

    Binary Search二分查找 作用:二分查找适用于有序的的数组或列表中,如果列表及数组中有n个元素,通过二分查找查询某一元素的位置需要的步骤是log2(n)(注:该log的底数是2) 1.Pyt ...

  2. STL模板整理 Binary search(二分查找)

    前言: 之前做题二分都是手动二分造轮子,用起来总是差强人意,后来看到STL才发现前辈们早就把轮子造好了,不得不说比自己手动实现好多了. 常用操作 1.头文件 #include <algorith ...

  3. LeetCode 704. Binary Search (二分查找)

    题目标签:Binary Search 很标准的一个二分查找,具体看code. Java Solution: Runtime:  0 ms, faster than 100 % Memory Usage ...

  4. lintcode:Binary Search 二分查找

    题目: 二分查找 给定一个排序的整数数组(升序)和一个要查找的整数target,用O(logn)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1. 样例 ...

  5. Leetcode704.Binary Search二分查找

    给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1. 示例 1: 输入: num ...

  6. 数据结构和算法设计专题之---二分查找(Java版)

    1.前提:二分查找的前提是需要查找的数组必须是已排序的,我们这里的实现默认为升序 2.原理:将数组分为三部分,依次是中值(所谓的中值就是数组中间位置的那个值)前,中值,中值后:将要查找的值和数组的中值 ...

  7. js基本算法:冒泡排序,二分查找

    知识扩充: 时间复杂度:算法的时间复杂度是一个函数,描述了算法的运行时间.时间复杂度越低,效率越高. 自我理解:一个算法,运行了几次时间复杂度就为多少,如运行了n次,则时间复杂度为O(n). 1.冒泡 ...

  8. LeetCode算法题-Binary Search(Java实现)

    这是悦乐书的第297次更新,第316篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第165题(顺位题号是704).给定n个元素的排序(按升序)整数数组nums和目标值,编 ...

  9. 501. Find Mode in Binary Search Tree查找BST中的众数

    [抄题]: Given a binary search tree (BST) with duplicates, find all the mode(s) (the most frequently oc ...

随机推荐

  1. modelsim-altera

    一. 1.  Go to the menu Tools > Options.  2.  In the “General” category, select “EDA Tool Options”. ...

  2. NativeBase准备工作

    环境 node>= 4.0 npm>= 3.0 rnpm (only if React Native version < 0.29) ReactNativeCLI  安装及运行 ht ...

  3. 整合Kafka到Spark Streaming——代码示例和挑战

    作者Michael G. Noll是瑞士的一位工程师和研究员,效力于Verisign,是Verisign实验室的大规模数据分析基础设施(基础Hadoop)的技术主管.本文,Michael详细的演示了如 ...

  4. linux uart驱动——uart原理(一)

    UART(Universal Asynchronous Receiver and Transmitter)通用异步收发器(异步串行通信口),是一种通用的数据通信协议,它包括了RS232.RS499.R ...

  5. git for windows 无法结束node进程(windows下杀进程)

    问题 windows 系统下,如果用CMD命令行启动node服务,Ctrl + C 即可结束命令 git bash 用起来比命令行方便,但是Ctrl + C 并不会结束node服务,再次启动会报如下错 ...

  6. python 基础 4.2 高阶函数上

    一.高阶函数 把函数当做参数传递的一种函数   1>map()函数 map函数是python内置的一个高阶函数,它接受一个函数f和一个list,并把list元素以此传递给函数f,然后返回一个函数 ...

  7. PHP、AJAX综合练习(增、删、改、查、分页、模糊查询)

    先来几张效果图 主页面分页显示: 关键字查询,关键字描红 添加数组,弹出窗口,点击保存,再不刷新页面的同时添加到网页数据 修改界面:弹出窗口,文本框中保留点击的车辆的原始信息 主页面代码 <me ...

  8. 通用安防摄像机通过RTSP转RTMP推流进行H5(RTMP/HLS)直播的方案

    EasyNVR摄像机无插件直播方案 随着互联网的发展,尤其是移动互联网的普及,基于H5.微信的应用越来越多,企业也更多地想基于H5.微信公众号来快速开发和运营自己的视频及视频相关性产品,那么传统的安防 ...

  9. Chrome性能分析工具lightHouse用法指南

    本文主要讲如何使用Chrome开发者工具linghtHouse进行页面性能分析. 1.安装插件 非常简单,点击右上角的“添加至Chrome”即可. 2.使用方式 1)打开要测试的页面,点击浏览器右上角 ...

  10. 【题解】Counting D-sets(容斥+欧拉定理)

    [题解]Counting D-sets(容斥+欧拉定理) 没时间写先咕咕咕. vjCodeChef - CNTDSETS 就是容斥,只是难了一二三四五\(\dots \inf\)点 题目大意: 给定你 ...