俊介三

一天更新一点,一天积累一点

导航

二分查找及其扩展

Posted on 2013-03-10 22:42  俊介三在前进  阅读(126)  评论(0)    收藏  举报

问题:给一个排好序的数组arr[9]={1,3,5,7,19,23,22,33,100};再给某个数k,看它是否在此数组中,如果在,返回它的index,否则返回-1。

使用遍历一遍查找的方法,最坏的时间复杂度是O(n).(假如第一个就找到了,时间复杂度是O(1),但这没有意义。一般情况,很可能找不到而变成就坏的情况。所以计算最坏时间复杂度非常有现实意义。)

当然,这题使用二分查找,时间复杂度为O(logn)

代码如下:

View Code
#include <stdio.h>

int binarySearch(int* arr, int start, int end, int n){

    int mid = (start+end)/2;
    if(arr[mid]==n) return mid;
    if(start>end) return -1;
    if(arr[mid]>n){
        binarySearch(arr,start,mid-1,n);
    }else{
        binarySearch(arr,mid+1,end,n);
    }
}

int main(){
    int arr[9]={1,3,5,7,19,23,22,33,100};
    int k;//the one I want to search.

    for(k=0;k<15;k++){
        int i = binarySearch(arr,0,8,k);
        if(i==-1) printf("k=%d not found!\n",k);
        else printf("The one is arr[%d]=%d\n",i,arr[i]);
    }
    
    return 0;
}

此题的一个扩展问题是:Given two sorted arrays A, B of size m and n respectively. Find the k-th smallest element in the union of A and B. You can assume that there are no duplicate elements.

这题也能用二分吗?参考这个详解http://leetcode.com/2011/01/find-k-th-smallest-element-in-union-of.html

Ai和Bj分别代表它们各自近K个的地方,即i=(k-1)*m/(m+n)  j=(k-1)*n(m+n);

如果Ai-1<Bj<Ai 那么Bj就是全部union的array的第k个了。同理,要检验一下Bj-1<Ai<Bj.

如果都不是,则判断Ai大还是Bj大,第k个肯定在它们之间,递归地查找它们之间的元素。

详细代码如下:

View Code
#include <stdio.h>
#include <assert.h>
#define INT_MIN -99999999
#define INT_MAX 99999999

int findKthSmallest(int A[], int m, int B[], int n, int k) {
  assert(m >= 0); assert(n >= 0); assert(k > 0); assert(k <= m+n);
   
  int i = (int)((double)m / (m+n) * (k-1));
  int j = (k-1) - i;
 
  //这个编程style貌似挺有用,老外喜欢严谨点,时不时assert一下,好debug以及提醒自己
  assert(i >= 0); assert(j >= 0); assert(i <= m); assert(j <= n);
  // invariant: i + j = k-1
  // Note: A[-1] = -INF and A[m] = +INF to maintain invariant
  int Ai_1 = ((i == 0) ? INT_MIN : A[i-1]);
  int Bj_1 = ((j == 0) ? INT_MIN : B[j-1]);
  int Ai   = ((i == m) ? INT_MAX : A[i]);
  int Bj   = ((j == n) ? INT_MAX : B[j]);
 
  if (Bj_1 < Ai && Ai < Bj)
    return Ai;
  else if (Ai_1 <= Bj && Bj <= Ai) //have duplicate elements or not.
    return Bj;
 
  assert((Ai > Bj && Ai_1 > Bj) || (Ai < Bj && Ai < Bj_1));
 
  // if none of the cases above, then it is either:
  if (Ai < Bj)
    // exclude Ai and below portion
    // exclude Bj and above portion
    return findKthSmallest(A+i+1, m-i-1, B, j, k-i-1);
  else /* Bj < Ai */
    // exclude Ai and above portion
    // exclude Bj and below portion
    return findKthSmallest(A, i, B+j+1, n-j-1, k-j-1);
}

int main(){
    int arr[9]={1,3,5,7,19,23,32,33,100};
    int arr2[5]={2,4,6,8,20};

    int i;
    for(i=1;i<10;i++){
        int ans = findKthSmallest(arr,9,arr2,5,i);
        printf("%d\n",ans);
    }

    return 0;
}