剑指Offer——二分查找算法

前言

本片博文主要讲解查找算法的相关知识。重点介绍二分查找。

二分查找算法是在有序数组中用到的较为频繁的一种查找算法,在未接触二分查找算法时,最通用的一种做法是,对数组进行遍历,跟每个元素进行比较,其时间为O(n).但二分查找算法则更优,因为其查找时间为O(lgn)。

在面试的时候二分查找是用的比较多一种查找算法,如何在面试官面前快速准确得的写出代码决定你是否能够被录取。以前一直以为二分查找很简单,所以就没怎么重视,但是真要在面试官面前对着黑板手写出来,还是漏洞百出。

1.二分查找的时间复杂度是O(log(n)),最坏情况下的时间复杂度是O(n)。

2.二分查找的一个条件是待查询的数组是有序的,我们假设这里的数组是升序的。

3.二分查找的主要思路就是设定两个指针start和end分别指向数组元素的首尾两端,然后比较数组中间结点arry[mid]和待查找元素。如果待查找元素小于中间元素,那么表明带查找元素在数组的前半段,那么将end=mid-1,如果待查找元素大于中间元素,那么表明该元素在数组的后半段,将start=mid+1;如果中间元素等于待查找元素,那么返回mid的值。

譬如数组{1, 2, 3, 4, 5, 6, 7, 8, 9},查找元素6,用二分查找的算法执行的话,其顺序为:

1.第一步查找中间元素,即5,由于5<6,则6必然在5之后的数组元素中,那么就在{6, 7, 8, 9}中查找;

2.寻找{6, 7, 8, 9}的中位数,为8,8>6,则6应该在8左边的数组元素中,那么就在{6,7,8}中查找;

3.寻找{6, 7, 8}的中位数,为7,7>6,则6应该在7左边的数组元素中,那么只剩下6,即找到了。

二分查找算法就是不断将数组进行对半分割,每次拿中间元素和goal进行比较。

源码

package cn.edu.ujn.demo;

public class BinarySearch {

/**
 * @param args
 */
public static void main(String[] args) {
int [] array = {1,2,3,4,4,7,12};
int len = array.length;
//System.out.println(binarySearchRecursion(array, 7, array[0], array[len-1]));
System.out.println(binarySearchRecursionNon(array, 7, array[0], array[len-1]));
}
/**
 * 二分查找(递归)
 * @param arry 递增数组
 * @param value 待查找数值
 * @param start 起始查找位置
 * @param end 末查找位置
 * @return
 */
private static int binarySearchRecursion(int arry[],int value,int start,int end)
{
    if(start > end)
        return -1;

    int mid=start + (end-start)/2;
    if(arry[mid] == value)
        return mid;

    else if(value < arry[mid])
    {
        end = mid - 1;
        return binarySearchRecursion(arry,value,start,end);
    }
    else
    {
        start = mid + 1;
        return binarySearchRecursion(arry,value,start,end);
    }
}
/**
 * 二分查找(非递归)
 * @param arry 递增数组
 * @param value 待查找数值
 * @param start 起始查找位置
 * @param end 末查找位置
 * @return
 */
private static int binarySearchRecursionNon(int arry[],int value,int start,int end)
{
while(start <= end){
    int mid=start + (end-start)/2;

    if(arry[mid] == value)
        return mid;

    else if(value < arry[mid])
    {
        end = mid - 1;
    }

    else
        start = mid + 1;
}
return -1;
}
}

在轮转后的有序数组上应用二分查找法

之前我们说过二分法是要应用在有序的数组上,如果是无序的,那么比较和二分就没有意义了。

不过还有一种特殊的数组上也同样可以应用,那就是“轮转后的有序数组(Rotated Sorted Array)”。它是有序数组,取其中某一个数为轴,将其之前的所有数都轮转到数组的末尾所得。比如{7, 11, 13, 17, 2, 3, 5}就是一个轮转后的有序数组。非严格意义上讲,有序数组也属于轮转后的有序数组——我们取首元素作为轴进行轮转。

下边就是二分查找法在轮转后的有序数组上的实现(假设数组中不存在相同的元素)

/**
 * 在轮转后的有序数组上应用二分查找法
 * @param array
 * @param low
 * @param high
 * @param target
 * @return
 */
int searchInRotatedSortedArray(int array[], int low, int high, int target)
{
    while(low <= high)
    {
        int mid = (low + high) / 2;
        if (target < array[mid])
            if (array[mid] < array[high])	// the higher part is sorted
                high = mid - 1; // the target would only be in lower part
            else 	// the lower part is sorted
                if(target < array[low])	// the target is less than all elements in low part
                    low = mid + 1;
                else
                    high = mid - 1;

        else if(array[mid] < target)
            if (array[low] < array[mid])	// the lower part is sorted
                low = mid + 1;	// the target would only be in higher part
            else 	// the higher part is sorted
               if (array[high] < target)   // the target is larger than all elements in higher part
                    high = mid - 1;
                else
                    low = mid + 1;
        else 	// if(array[mid] == target)
            return mid;
    }
    return -1;
}

对比普通的二分查找法,为了确定目标数会落在二分后的哪个部分,我们需要更多的判定条件。但是我们还是实现了O(log n)的目标。

二分查找法的缺陷

二分查找法的O(log n)让它成为十分高效的算法。不过它的缺陷却也是那么明显的。就在它的限定之上:

必须有序,我们很难保证我们的数组都是有序的。当然可以在构建数组的时候进行排序,可是又落到了第二个瓶颈上:它必须是数组。

数组读取效率是O(1),可是它的插入和删除某个元素的效率却是O(n)。因而导致构建有序数组变成低效的事情。

解决这些缺陷问题更好的方法应该是使用二叉查找树了,最好自然是自平衡二叉查找树了,自能高效的(O(n log n))构建有序元素集合,又能如同二分查找法一样快速(O(log n))的搜寻目标数。

     我们知道在效率方面,传值调用要比传址调用来的低,因为传值调用要进行一次变量的拷贝,而传址调用则是直接对这个变量进行操作。因此在编程中我们应该尽量将参数改为传址调用。

美文美图

剑指Offer——二分查找算法的更多相关文章

  1. 剑指offer—第二章算法之二分查找(旋转数组的最小值)

    旋转数组的最小数字 题目:把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如:数组{3,4,5,1,2}为{1,2,3,4, ...

  2. 剑指offer—第二章算法之快速排序

    算法:排序和查找(二分查找,归并排序,快速排序),位运算等. 查找:顺序查找,哈希查找,二叉排序树查找,哈希表. 二分查找可以解决:"旋转数组中的最小数字","数字在排序 ...

  3. 剑指offer 6.查找和排序 旋转数组的最小数字

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...

  4. 剑指OFFER数据结构与算法分类

    目录 数据结构 算法 数据结构 数组 有序二维数组查找 数组相对位置排序 数组顺时针输出 把数组排成最小的数 数组中的逆序对 扑克牌顺子 数组中重复的数字 构建乘积数组 链表 链表反向插入ArrayL ...

  5. 《剑指offer》查找二维数组内元素 c++

    在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序. 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. cl ...

  6. 《剑指offer》内容总结

    (1)剑指Offer——Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是统计和排序大量的字符串(但不仅限于字符串),所以经常 ...

  7. 【剑指offer】二分查找二维数组

    1 2 3 4 5 6 7 8 9 3 3 1 2 3 4 5 6 7 8 9 10 3 3 12 2 3 4 5 6 7 8 9 10 例子输出: Yes No No 时间限制:1 秒 内存限制:3 ...

  8. 【剑指offer】11--旋转数组的最小数字(二分查找)

    原创博文,转载请注明出处! # 本文是牛客网<剑指offer>刷题笔记 1.题目 旋转数组的最小数字:输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1 ...

  9. 剑指offer计划5(查找算法中等版)---java

    1.1.题目1 剑指 Offer 04. 二维数组中的查找 1.2.解法 其实就是暴力解法的升级版,从最后一行开始判断,通过num当前的大小, 如果还是大于目标值则行数-1,若是小于则列数+1 1.3 ...

随机推荐

  1. 【USACO17JAN】Promotion Counting晋升者计数 线段树+离散化

    题目描述 The cows have once again tried to form a startup company, failing to remember from past experie ...

  2. PostgreSQL 查看单表大小

    1. 在数据库中查单个表 select pg_size_pretty(pg_relation_size('table_name')); 2. 查出并按大小排序 SELECT table_schema ...

  3. Maven之自定义archetype生成项目骨架

    Maven之自定义archetype生成项目骨架(一) http://blog.csdn.net/sxdtzhaoxinguo/article/details/46895013

  4. node上传文件并在网页中展示

    一.需求 1.当用户请求http://domain/start时,可以看到一个欢迎页面,页面上有一个文件上传的表单. 2.用户可以选择一个图片并提交表单,随后文件将被上传到http://domain/ ...

  5. 通过内核修改centos密码

    在开机启动的时候按键盘上的"E"键会进入如下界面. 选择相应的内核,再次按"E",出现下图,选择第二项,再次按"E"键 经过第二步,这个画面 ...

  6. Node.js 虚拟机

    稳定性: 3 - 稳定 可以通过以下方法访问该模块: var vm = require('vm'); JavaScript 可以立即编译立即执行,也可以编译,保存,之后再运行. vm.runInThi ...

  7. Go 语言结构

    Go Hello World 实例 Go 语言的基础组成有以下几个部分: 包声明 引入包 函数 变量 语句 & 表达式 注释 接下来让我们来看下简单的代码,该代码输出了"Hello ...

  8. SSM实现秒杀系统案例

    ---------------------------------------------------------------------------------------------[版权申明:本 ...

  9. 安卓7.1 新特性Shortcut

    介绍 Shortcut 是谷歌在API25提出来的 类似苹果3D touch 但是没有压力感应.在安卓中完全就是长按. 来看下效果吧: 是不是很赞? 那么请随本文一起学习吧 更新 新建项目 在你项目下 ...

  10. The new powerful SQL executing schedule monthly or weekly in DB Query Analyzer 7.01

    1 About DB Query Analyzer DB Query Analyzer is presented by Master Genfeng,Ma from Chinese Mainland. ...