二分法查找

今天被要求写一个二分查找,几乎不到3分钟,我凭借一些对二分查找的印象写出了一个“二分查找”。但随后被告知存在错误。

通过这件事我明白了,光有想法是不够的,   把代码实际写出来才比较踏实!!

一个 朴素的二分查找

 

 

  
  
  
  
  1. public static int binarySearch(int[] array, int low, int high, int tar){  
  2.     int m;  
  3.     while(low <= high){  
  4.         m = (low+high)/2;  
  5.         if(array[m] == tar){  
  6.             return m;  
  7.         }else if(array[m] > tar){  
  8.             high = m - 1;  
  9.         }else if(array[m] < tar){  
  10.             low = m + 1;  
  11.         }  
  12.     }  
  13.     return -1;  

二分查找的原理很简单,边界问题容易出错。

8和10行保证了查找的范围每次都再缩小。真正的写出它时,我才发现之前我对二分查找一无所知。

 

 

下一话题:

面试的时候,有一个问题总会被千百遍的问到。1-n个数顺序排列  有一个数出现了2次。请找出这个数。虽然遍历也能找出,但是面试官总是希望应聘者使用除了遍历的方法........

显然这是二分法应用的一个典型,我们可以凭借对上段代码的修改来完成这个函数

 

  
  
  
  
  1. public static int search4Double(int[] array, int low, int high){  
  2.     if(high-low>1){  
  3.         int m = (low+high)/2;  
  4.         if(array[m] < (m+1)){  
  5.             return search4Double(array, low, m);  
  6.         }else {  
  7.             return search4Double(array, m, high);  
  8.         }  
  9.     }  
  10.     else 
  11.         return array[low];  

 我们这里用Double数代表重复的数 的意思。

我们这里的判断是:当第二个Double数位于m(中点)或比m小时,会导致array[m]没有达到预期的(m+1)(下标从0开始,所以加1)

当第二个Double的下标比m大时,array[m]==(m+1)

同时为了最终锁定Double数,Double数必须每次都被分到一侧。5和7没用m+1 m-1  就是为了保证这点。同时5和7还能保证当n>2时,查找范围会缩小。

最终循环下去,n=2时,一定是2个Double数。2行保证了n=2时跳出循环,并返回找到的Double数。

 

其实这个问题和第一个问题看起来很相似,实际上完全不同。

第一个问题的二分法,它在每次循环做的事情是:看看array[m]是不是我想要的,不是的话去前边或者后边找。

而第二个问题做的事情是:现在不急于找出谁是Double数,只是先缩小范围,当只剩下2个数的时候,就是Double数

其实第二问题也可以写第一个问题的那种方式,但如果想判断中点array[m]是不是Double数,你需要做2次额外判断array[m-1]==array[m] array[m]==array[m+1] ,只有这样,你才能在缩小范围的时候大胆的写上 m+1 或 m-1

 

以后学习要多总结,要不学多少忘多少...

你可能感兴趣的:(java,二分法,数据结构和算法)