二分查找的递归和非递归方式

1.典型的二分查找(注意二分查找的适用条件是递增的数组)

1).递归方式

class BinaryTree
{
	public static void main(String[] args)
	{
		int[] a = {1,3,4,6,8,9,10,11,23};
		System.out.println(search(a,12,0,a.length-1));
	}
	
	public static int search(int[] a,int data,int low,int high)
	{
		if(low<=high)					
			int pivot = (low+high)/2;
			if(data==a[pivot])
				return pivot;
			else if(data>a[pivot])
			{
				return search(a,data,pivot+1,high);
			}
			else 
			{
				return search(a,data,low,pivot-1);
			}
		}
		else
		{
			return -1;			//通过返回-1,表示找不到
		}	
	}
}

2).非递归方式

class BinaryTree
{
	public static void main(String[] args)
	{
		int[] a = {1,3,4,6,8,9,10,11,23};
		System.out.println(search(a,11));
	}
	
	public static int search(int[] a,int data)
	{
		int low = 0;
		int high = a.length - 1;
		while(low<=high)
		{
			int pivot = (low + high)/2;
			if(data==a[pivot])
				return pivot;
			else if(data>a[pivot])
			{
				low = pivot + 1;
			}
			else
			{
				high = pivot -1;
			}
		}
		return -1;
	}
}

2.使用二分查找的思想来解题:

1.题目描述  (剑指offer 面试题11 旋转数组)

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0

分析:本题给出的数组一定程度上是排序的,因此可以试者使用二分查找法寻找最小值。

1)使用low和high分别指向数组的第一个元素和最后一个元素。如果没有旋转第一个元素是小于等于最后一个元素,旋转后第一个元素应该是大于等于最后一个元素(等于是有重复元素的情况)

2)中间元素大于第一个元素,此时说明中间元素位于前面的递增子数组中,此时最小元素位于中间元素后面的。我们可以让low指向中间元素。

3)中间元素小于第一个元素,此时说明中间元素位于后面的递增子数组中,此时最小元素位于中间元素的前面,我们可以让high指针指向中间元素。

4)通过2)3)可以缩小寻找的范围,重复2)3)直到low+1=high时,high指向的元素就是最小元素

5)考虑几种特殊情况,如果把排序数组的前面0个元素搬到最后面,即排序数组本身,此时第一个元素就是最小的。

6){1,0,1,1,1}和{1,1,1,0,1}都可看成是递增排序数组{0,1,1,1,1}的旋转,此时mid,low,high指向的数都相同,第一种情况下,中间元素位于后面的子数组,第二种情况,中间数字位于前面的子数组,此时只能采用顺序寻找的方式。

代码实现:

public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array.length==0){
            return 0;
        }
        if(array[0]<array[array.length-1])
            return array[0];
        return binarySearch(array,0,array.length-1);
    }
    public int binarySearch(int[] a,int low,int high){
      while(a[low]>=a[high]){    //这边为什么要等于号
          if(low+1==high){
              return a[high];
          }
          //如果下标low,high和mid相等,这时候就需要顺序查找
          int mid = (low + high)/2;
          if(a[low]==a[high]&&a[low]==a[mid]){
              return MininOrder(a,low,high);
          }
          if(a[mid]>=a[low]){            //这边的等于号不能丢
              low = mid;
          }else if(a[mid]<=a[low]){
              high = mid;
          }
      }
      return a[0];
    }
    public int MininOrder(int[] a,int low,int high){
        int min = a[low];
        for(int i=low+1;i<=high;i++){
            if(a[i]<min){
                min = a[i];
            }
        }
        return min;
    }
}

2. 题目描述(剑指offer在排序数组中查找数字)
统计一个数字在排序数组中出现的次数。例如排序数组{1,2,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4。

思路:该题的数组是一个排序数组,思路找到第一次出现3的位置,和最后出现3位置,两者相减就得到3的个数。可以考虑使用二分查找法,如上面的数字所示,典型的二分查找在找到数字3后就停止了,该题中可以在找到3后(第一次找到的是中间的3),判断3前面的数字是不是3(前面有数字的情况下,如果前面没有数字,那么这个3肯定就是第一出现的3),如果前面的数字不是3,那么找到的3就是一次出现的3,而如果前面的数字也是3,那么就在数组的前半段继续查找3,直到找到第一次出现3的位置。同样的方法找到最后一个出现3的位置,将两个位置相减就得到出现的个数。

代码实现:

class Solution {
    public int GetNumberOfK(int [] array , int k) {
        int N = array.length - 1;
        int i = getFirstK(array,k,0,N);
        System.out.println("i: "+i);
        int j = getLastK(array,k,0,N);
        System.out.println("j: "+j);
        if(i>-1&&j>-1)            
        	return j-i+1;
        return 0;
    }
    public int getFirstK(int[] array,int k,int low,int high){
    	while(low<=high){
    		int mid = (low+high)/2;
    		if(array[mid]<k)
    			low = mid + 1;
    		else if(array[mid]>k)
    			high = mid -1;
    		else{                     //找了数字k,还需继续判断这个数字是不是第一次出现
    			if(mid==0)        //如果前面没有数字了,这个数字就是第一次出现了
    				return mid;
    			else if(mid-1>=0&&array[mid-1]!=k){    //如果前面的数字和这个数字不等,那么也是第一个出现了
    				return mid;
                }
    			else{
    				high = mid - 1;
                }
            }
        }
		return -1;                //如果没有找到该数字,返回-1
    }
    public int getLastK(int[] array,int k,int low,int high){
    	if(low<=high){
    		int mid = (low+high)/2;
    		if(array[mid]>k){
    			return getLastK(array,k,low,mid-1);
            }
    		else if(array[mid]<k){
    			return getLastK(array,k,mid+1,high);
            }
    		else{
    			if(mid==array.length-1){
    				return mid;
                }
    			if(array[mid+1]<=array.length-1&&array[mid+1]==k){
    				return getLastK(array,k,mid+1,high);
                }
    			else{
    				return mid;
                }
            }
        }
    	return -1;
    }
}

猜你喜欢

转载自blog.csdn.net/chenkaibsw/article/details/80059835