前言:

二分搜索是一个非常常见的面试题目,它具有非常广泛的用途。熟练的掌握二分搜索的基本形式和他的变式是非常重要的。接下来我们将使用java实现一些常见的有关二分搜索的问题。

具体内容:

1.二分搜索的基本形式:在一个有序的数组中查找k,如果k存在的话就返回k的下标,否则就返回-1

基本的二分搜索要注意以下几个问题:

(1)边界条件:如果k比array[0]小,或者k比array[length-1]大的话,那就说明k是不存在的;如果数组的长度为0那么也说明k是不存在的

(2)middle的求法:middle = low+(high-low)/2

以下是具体代码:

  1. //在一个有序无重复数组中找到和k相等的数的位置,找不到就返回-1
  2. public static int binarySearchUnique(int[] array, int k){
  3. int length = array.length;
  4. int low = 0, high = length-1;
  5. if(low>high || k<array[low]||k>array[high]){
  6. return -1;
  7. }
  8. while(low<=high){
  9. int middle = low+(high-low)/2;
  10. if(array[middle] == k){
  11. return middle;
  12. }else{
  13. if(array[middle]>k){
  14. low = middle +1;
  15. }else{
  16. high = middle -1;
  17. }
  18.  
  19. }
  20. }
  21. return -1;
  22. }

2.二分搜索进阶版:在一个有序有重复的数组中找到大于等于k的最小下标,如果不存在就返回-1

思想:(1)将k和array[middle]的值进行对比,如何前者更大的话,那么说明low=middle+1;否则说明high=middle;这里为什么不是high=middle-1,因为有可能array[middle-1]比k要小,那么这个时候high就不是大于等于k的元素的最小下标所在的上限。

(2)外层循环条件由low<=high;改成了low<high;因为如果是low等于high的话,由于high=middle,那么有可能会陷入死循环

(3)跳出循环的条件是low等于high。此时返回的low就是所求的值。

注意的点:(1)边界情况的判断:数组的长度要大于0

(2)循环的跳出条件是low<high

(3)最后的low就是所求的值

  1. //在一个有序有重复的数组中找到和k相等的数的最小下标,找不到就返回-1
  2. //search the position for the number which is the first number of <=k
  3. public static int binarySearchMany(int[] array, int k){
  4. int high = array.length -1;
  5. int low = 0;
  6. if(low>high||k>array[high]){
  7. return -1;
  8. }
  9. while(low<high){
  10. int middle = low+(high-low)/2;
  11. if(array[middle]<k){
  12. low = middle + 1;
  13. }else{
  14. high = middle;
  15. }
  16. }
  17. return low;
  18. }

3.二分搜索进阶版:在一个有序的无重复的前后轮转的数组中找到k的位置,如果k不存在的话返回-1
思想:将k值和array[middle],array[high]以及array[low]分别比较:

当 k==array[middle]时,说明找到了

当array[middle]<k<=array[high],说明low=middle+1;

当array[middle]<k&&array[high]<k,我们只能知道high = high -1;

当array[low]<=k<array[middle], 说明high = middle -1;

当array[low]>k&&array[middle]>k,我们只能知道low = low+1;

  1. //给定一个有序递增数组,不含有重复元素,但是这个有序数组发生了rotate,用二分查找找到k的位置,k不存在的话返回1
  2. public static int binarySearchRotate(int[] array, int k){
  3. int length = array.length -1;
  4. int low = 0, high = length;
  5. if(low>high){
  6. return -1;
  7. }
  8. while(low<=high){
  9. int middle = low+(high - low)/2;
  10. if(array[middle]==k){
  11. return middle;
  12. }else{
  13. if(array[low]<=k&&array[middle]>k){
  14. high = middle -1;
  15. }else if(array[low]>k&&array[middle]>k){
  16. low += 1;
  17. }else if(array[high]>=k&&array[middle]<k){
  18. low = middle+1;
  19. }else{
  20. high = high-1;
  21. }
  22.  
  23. }
  24. }
  25. return -1;
  26.  
  27. }

4.二分搜索进阶版:在一个有序的无重复的数组中找到满足array[i]=i的最小下标

思想:

(1)array[middle]>=middle,那么说明下标大于middle的那部分数据都是不可能的

(2)array[middle]<=middle, 那么说明下标小于middle的那部分数据都输不可能的

边界:如果array[0]>0的话,那么是不可能找到的,同理array[length-1]也不能小于length;数组的长度要大于0

  1. //给定一个有序递增数组arr,其中不含有重复元素,请找到满足arr[i]==i条件的最左的位置。如果所有位置上的数都不满足条件,返回-1
  2. public static int binarySearchIndex(int[] array){
  3. int low = 0, high = array.length-1;
  4. if(low>high||array[low]>0||array[high]<high){
  5. return -1;
  6. }
  7. while(low<high){
  8. int middle = low +(high-low)/2;
  9. if(array[middle]>=middle){
  10. high = middle - 1;
  11. }else if(array[middle]<middle){
  12. low = middle + 1;
  13. }
  14. }
  15. if(array[low]==low){
  16. return low;
  17. }
  18. return -1;
  19. }

测试:
对以上的代码进行测试:

1.先写出朴素的搜索函数:

  1. // the common method to find the k
  2. public static int findk(int[] array, int k){
  3. for(int i = 0; i<array.length; i++){
  4. if(array[i]==k){
  5. return i;
  6. }
  7. }
  8. return -1;
  9. }
  10. // the common method to find the first value which is >=k
  11. public static int findFirstValue(int[] array, int k){
  12. for(int i = 0; i<array.length; i++){
  13. if(array[i]>=k){
  14. return i;
  15. }
  16. }
  17. return -1;
  18. }
  19. //the common method to find first number which satisfy array[i] = i
  20. public static int findFirstIndex(int[] array){
  21. for(int i=0; i<array.length; i++){
  22. if(array[i]==i){
  23. return i;
  24. }
  25. }
  26. return -1;
  27. }

2.进行测试

  1. public static void main(String args[]){
  2. int N = 1000000;
  3. Random rand = new Random();
  4. double same = 0.0;
  5. while(N>0){
  6. int n = rand.nextInt(50)+1;
  7. int k = rand.nextInt();
  8. int[] array = new int[n];
  9. for(int i = 0; i<n; i++){
  10. array[i] = rand.nextInt();
  11. }
  12. Arrays.sort(array);
  13. int position;
  14. position = binarySearchMany(array, k);
  15. int position2 = findFirstValue(array, k);
  16. if(position == position2){
  17. same++;
  18. }else{
  19. System.out.println(k);
  20. for(int i=0; i<n; i++){
  21. System.out.print(array[i]+" ");
  22. }
  23. System.out.println();
  24. System.out.println(position);
  25. System.out.println(position2);
  26. }
  27. N--;
  28. }
  29. double ratio = same/1000000;
  30. System.out.println(ratio);
  31. }

3.经过测试以上代码皆为正确代码

有关于二分搜索的常见问题(java实现)的更多相关文章

  1. [Spring常见问题]java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

    这个问题是因为部署在tomcat下的项目中没有springweb包 但是问题来了,但是我的项目中有呀,maven都引了呀,然后我就懵B啦!看到这个博客我就豁然开朗了:http://my.oschina ...

  2. JAVA面向对象初步知识总结:封装、继承、多态

    1.封装 把数据和方法包装进类中,以及具体实现的隐藏,常共同被称作是是封装.其结果是一个同时带有特征和行为的数据类型.所谓具体实现的隐藏是通过访问权限控制实现的.JAVA 子类重写继承的方法时,不可以 ...

  3. Java基础面试题总结

    目录 索引 Java基础知识篇 Java web基础知识总结 Java集合篇常见问题 Java基础知识篇 面向对象和面向过程的区别 面向过程: 优点:性能比面向对象高,因为类调用时需要实例化,开销比较 ...

  4. java构建工具——ant使用

    Ant是跨平台的构建工具,它可以实现项目的自动构建和部署等功能.在本文中,主要让读者熟悉怎样将Ant应用到Java项目中,让它简化构建和部署操作. 一.安装与部署 1.1 下载 下载地址:https: ...

  5. day01<计算机基础知识&Java语言基础>

    计算机基础知识(计算机概述) 计算机基础知识(软件开发和计算机语言概述) 计算机基础知识(人机交互) 计算机基础知识(键盘功能键和快捷键) 计算机基础知识(如何打开DOS控制台) 计算机基础知识(常见 ...

  6. 【Java】3到5年开发常见的Java面试题

    一.Java基础和高级 String类为什么是final的. HashMap的源码,实现原理,底层结构. 反射中,Class.forName和classloader的区别 session和cookie ...

  7. 2019滴滴java面试总结 (包含面试题解析)

    2019滴滴java面试总结  (包含面试题) 本人6年开发经验.今年年初找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.滴滴等公司offer,岗位是既有php也有Java后端开发,最终选择去了滴滴 ...

  8. 2019头条java面试总结 (包含面试题解析)

    2019滴滴java面试总结  (包含面试题) 本人8年开发经验.今年年初找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.滴滴等公司offer,岗位是Java后端开发. 面试了很多家公司,感觉大部分 ...

  9. 挑战10个最难的Java面试题(附答案)【上】【华为云技术分享】

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/devcloud/article/deta ...

随机推荐

  1. 安装Compass时不能访问服务器的问题

    今天安装Compass,居然老是提示网络问题,后来根据错误提示,发现带https的域名是访问不了的,是是SSL问题.后来搜了一下,在stackoverflow找到一个人说,将https的去掉就好了.具 ...

  2. Cannot start service MSSQL$MICROSOFT##WID on computer

    在做ADFS部署过程中配置ADFS服务时遇到如下问题 检查系统日志错误日志如下,很明显"NT SERVICE\MSSQL$MICROSOFT##WID"这个账户不在log on a ...

  3. iOS基础常用细节问题处理65条

    1. 不可变数组  转变为可变数组  //声明实例变量的数组  必须记得实现 //对于遍历数组找到对象后 如果还需要查找 记得先结束 再查找(return/break) NSArray * arr = ...

  4. Linux学习笔记 --iptables防火墙配置

    iptables防火墙配置 一.防火墙简介 1.功能: 1)通过源端口,源IP地址,源MAC地址,包中特定标记和目标端口,IP,MAC来确定数据包是否可以通过防火墙 2)分割内网和外网[附带的路由器的 ...

  5. Android下NDK开发环境搭建

    Android下NDK开发环境搭建 1.     AndroidNDK安装与配置 1.1  NDK简介 Android NDK是一套允许开发人员使用本地代码(如C/C++)进行Android APP部 ...

  6. 鹅场offer已Get,下周签约,终于能静下心来总结总结

    2015年9月20号下午,接到腾讯总部的电话,确定了offer相关信息,算是正式get了鹅场的offer,坐等下个周一周二的签约会. 心路篇 2015年2月:已经2月份了,自己在大学的时光已经来到了比 ...

  7. myfirstBI项目总结

    app 应用信息统计: saiku安装:http://blog.csdn.net/longshenlmj/article/details/17359645 workbench解压即用,http://b ...

  8. Swift之GCD使用指南1

    Grand Central Dispatch(GCD)是异步执行任务的技术之一.一般将应用程序中记述的线程管理用的代码在系统级中实现.开发者只需要定义想执行的任务并追加到适当的Dispatch Que ...

  9. 阿里云 云服务器 CentOS 5.8 安装 php 5.4

    1.安装php http://webtatic.com/packages/php54/ 2.安装mysql http://webtatic.com/packages/mysql55/ 3.修改mysq ...

  10. 跟我一起写Makefile(转)

    这是我见过最全的Makefile编写指南:跟我一起写Makefile. PDF版本可以从这里下载得到.