花了半天把二分查找的几种都写了一遍。验证了一下。二分查找的正确编写的关键就是,确保循环的初始、循环不变式能够保证一致。

可以先从循环里面确定循环不变式,然后再推导初始条件,最后根据循环不变式的内容推导出结果。

1. 普通的二分查找

第一版本:

 //first version
int find(int arr[], int n, int target) {
int l = , r = n - ;
while (l <= r) {
int m = l + (r - l) / ;
if (arr[m] == target) return m;
else if (arr[m] < target) {
l = m + ;
} else {
r = m - ;
}
}
return -;
}

循环内部有三次比较,一般来说,相等的操作只需要判断一次,所以最好是放在循环最外面判断。

注意这里因为提到外面判断相等的情况了,那么循环退出条件就可以改为l <r, 在循环中不需要判断l == r的情形。

 //second version
int findLeft(int arr[], int n, int target) {
int l = , r = n - ; // [l, r]
while (l < r) {
int m = l + (r - l) / ; // l < r => m < r
if (arr[m] < target) {
l = m + ; // l <= m => l need to be added by one ensuring l is always increasing; and arr[l] <= target
} else {
r = m; // target <= arr[m], [l, r], m < r => if arr[m] == target, we still decrease r, so what we found is the lower_bound
}
} // [l, r] && r >= l => if (arr[l] == target) => return l;
if (l < n && arr[l] == target) return l;
else return -;
}

2. 查找最左边的值

同上面的version 2.

关键就是,处理相等的情况。由于是要求最左的位置,所以遇到相等时候,仍要把区间往左移。所以这里是用了r=m。(因为m恒小于r)。

3. 查找最右边的值

这里的关键同样是处理相等的情况。要求的是最右的位置,那么遇到相等的时候,还是要把区间右移,所以这里是l=m+1。之所以要加1,就是因为l<=m的,为了确保循环一定能够退出,要加1,才能确保每次循环,区间都在缩小。但是加了1之后,变成了target==arr[m]的时候,l=m+1, 也就是target > arr[l]。所以最终的结果就是l-1。从这里再去推导初始化的时候,l和r的取值。因为区间是[l-1,r),所以l=1,r=n。

 int findRight(int arr[], int n, int target) {
int l = , r = n; // [l - 1, r)
while (l < r) {
int m = l + (r - l) / ;
if (arr[m] > target) { // ensuring target < arr[r] && target > arr[l], [l - 1, r)
r = m; // l < r => m < r, [l - 1, r)
} else {
l = m + ; // l <= m, when target == arr[m], l is still increasing, [l - 1, r), target >= arr[l - 1] = arr[m]
}
} // [l-1, r)
if (l - >= && arr[l - ] == target) return l - ;
else return -;
}

4. 查找倒数第一个比它小的数;

 int findLastSmall(int arr[], int n, int target) {
int l = , r = n - ;
// [l, r]
while (l < r) {
int m = l + (r - l) / ;
if (arr[m] >= target) {
r = m; // target <= arr[r]
} else {
l = m + ; // target > arr[m] => target >= arr[m+1], [l, r]
}
} // target is in [l, r], so the last smaller number is r
if (target > arr[l]) return l;
return l - ;
}

因为循环中确保了target >= arr[l] && target <= arr[r],那么我们要判断target[l]是否等于target,如果等于,返回的是l-1。否则返回的就是l。

5. 查找第一个比它大的数;

int findFirstLarge(int arr[], int n, int target) {
int l = , r = n;
// [l - 1, r)
while (l < r) {
int m = l + (r - l) / ;
if (arr[m] <= target) { // target >= arr[l - 1]
l = m + ; // l is increasing, [l - 1, r)
} else { // target < arr[m]
r = m; // target < arr[r],[l - 1, r)
}
}
// target is in [l - 1, r), so the first larger number is r
return r;
}

这个比较简单,因为循环确定target>=arr[l]&&target < arr[r],那么第一个比target大的数肯定就是arr[r]。

Worst case performance: O(log n)
Best case performance: O(1)
Average case performance: O(log n)
Worst case space complexity: O(1)

今天算是把怎么验证程序的正确性研究了一天了。。。20140923

Algorithm | Binary Search的更多相关文章

  1. [Algorithms] Binary Search Algorithm using TypeScript

    (binary search trees) which form the basis of modern databases and immutable data structures. Binary ...

  2. 【437】Binary search algorithm,二分搜索算法

    Complexity: O(log(n)) Ref: Binary search algorithm or 二分搜索算法 Ref: C 版本 while 循环 C Language scripts b ...

  3. js binary search algorithm

    js binary search algorithm js 二分查找算法 二分查找, 前置条件 存储在数组中 有序排列 理想条件: 数组是递增排列,数组中的元素互不相同; 重排 & 去重 顺序 ...

  4. 2 - Binary Search & LogN Algorithm - Apr 18

    38. Search a 2D Matrix II https://www.lintcode.com/problem/search-a-2d-matrix-ii/description?_from=l ...

  5. 2 - Binary Search & LogN Algorithm

    254. Drop Eggs https://www.lintcode.com/problem/drop-eggs/description?_from=ladder&&fromId=1 ...

  6. [Algorithm] Delete a node from Binary Search Tree

    The solution for the problem can be divided into three cases: case 1: if the delete node is leaf nod ...

  7. [Algorithm] Check if a binary tree is binary search tree or not

    What is Binary Search Tree (BST) A binary tree in which for each node, value of all the nodes in lef ...

  8. [Algorithm] Count occurrences of a number in a sorted array with duplicates using Binary Search

    Let's say we are going to find out number of occurrences of a number in a sorted array using binary ...

  9. leetcode -- Convert Sorted List to Binary Search Tree

    Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...

随机推荐

  1. CentOS 7 (RHEL 7)服务管理命令的变化

    CentOS 7 (RHEL 7)带来了新的服务管理命令,为了保持兼容原有的命令仍可以使用,以下是新旧命令的对照. 启动.停止.重启.重载.检查服务:6: service httpd start|st ...

  2. tp框架之分页与第三方类的应用

    1.先把分页类放在根目录下,比如放在某个模块下 2.在类里面写入命名空间,注意类名的格式(类名要与里面的方法名一致) 3.在需要的方法里面按照路径进行实例化,然后就可以使用了 方法: public f ...

  3. 【Java EE 学习 74 下】【数据采集系统第六天】【使用Jfreechart的统计图实现】【将JFreechart整合到项目中】

    之前说了JFreechart的基本使用方法,包括生成饼图.柱状统计图和折线统计图的方法.现在需要将其整合到数据采集系统中根据调查结果生成三种不同的统计图. 一.统计模型的分析和设计 实现统计图显示的流 ...

  4. socket 收发报文小程序

    需要注意,由于是从文件读取,而WINDOWS自带的文本文档程序,亲测对于UTF-8文件会不可见地在文件头多出3个字节.另外回车换行也是不可见字节,需要考虑到. package com.test.com ...

  5. [译]:Xamarin.Android开发入门——Hello,Android Multiscreen深入理解

    原文链接:Hello, Android Multiscreen_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android Multiscreen深入理解. 本 ...

  6. cmake cannot find package

    cmake 找不到package,如 find_package (OpenMesh REQUIRED) 出现错误 在项目的文件夹中找到 FindOpenMesh.cmake 文件,将其所在路径添加到 ...

  7. 【转载】VS2012的打包方法

    上篇博客把收费系统的总体设计进行了一遍讲解,讲解的同时掺杂了些有关.NET编译机制的总结.程序编写测试完成后接下来我们要做的是打包部署程序,但VS2012让人心痛的是没有了打包工具.不知道出于什么原因 ...

  8. POJ 3415 Common Substrings ——后缀数组

    [题目分析] 判断有多少个长度不小于k的相同子串的数目. N^2显然是可以做到的. 其实可以维护一个关于height的单调栈,统计一下贡献,就可以了. 其实还是挺难写的OTZ. [代码] #inclu ...

  9. openfl使用64位的ndk时,编译报错的问题!

    当使用64位的ndk时,如果使用openfl test android运行android测试,应该会出现 arm-linux-androideabi-g++:找不到这个命令的错误. 原因是,haxel ...

  10. 2016 Multi-University Training Contests

    2016 Multi-University Training Contest 1 2016 Multi-University Training Contest 2 2016 Multi-Univers ...