二分查找的改进

public static int binarySearch(int[] arr,int target){
  //设置左边位置
  int left=0;
  //设置右边位置
  int right=arr.length-1;
  //循环条件:如果左边位置小于等于右边位置
  while(left<=right){
    //中间位置等于(左边+右边)/2
    int mid =(right+left)>>>1;
    //如果目标等于中间位置就返回
    if(arr[mid]==target){
      return mid;
    }else if(arr[mid]<target){
      //如果中间位置小于目标位置
      //左边位置等于中间位置+1
      left=mid+1;
    }else if(arr[mid]>target){
      //如果中间位置大于目标位置
      //右边位置等于中间位置-1
      right=mid-1;
    }
  }
  //如果没有找到就返回 -1
  return -1;
}

原二分查找如果元素在最左边和元素在最右边的情况的循环次数差了1倍

改进后

public static int binarySearch2(int[] a ,int target){
        //设置左边位置
        int i=0;
        //设置右边位置
        int j=a.length;
        //循环条件:至少还有两个或以上的元素可以继续查找
        while(1<j-i){
            //中间位置等于(左边+右边)/2
            int m=(i+j)>>1;
            //如果目标小于中间位置,右边位置等于中间位置
            if(target<a[m]){
                j=m;
            }else{
                //否则,左边位置等于中间位置
                i=m;
            }
        }
        if(a[i]==target){
            //如果找到了,i就是索引位置
            return i;
        }else{
            //找不到就返回-1
            return -1;
        }
    }

1.左闭右开的区间,i指向的可能是目标,而j指向的不是目标
2.不在循环内找出,而是等范围内只剩下i时,退出循环,在循环外比较a[i]与target
3.循环内的平均比较次数减少了
4.时间复杂度都是⊙(㏒(n))
缺点是:最好的情况时的时间复杂度由O(1)变为了⊙(㏒(n))

要求:用二分查找,找出重复数据中最靠左的那一个
代码示例

public static int binarySearchLeftmost1(int[] a,int target){
  int i =0;
  int j =a.length-1;
  //候选位置
  int candidate=-1;
  while(i<=j){
    int m=(i+j)>>>1;
    if(target<a[m]){
      j=m-1;
    }else if(a[m]<target){
      i=m+1;
    }else{
      //记录候选位置
      candidate=m;
      j=m-1;
    }
  }
  return candidate;
}

要求:用二分查找,找出重复数据中最靠右的那一个
代码示例

public static int binarySearchRightmost1(int[] a,int target){
  int i =0;
  int j =a.length-1;
  int candidate=-1;
  while(i<=j){
    int m =(i+j)>>>1;
    if(target<a[m]){
      j=m-1;
    }else if(a[m]<target){
      i=m+1;
    }else{
      candidate=m;
      i=m+1;
    }
  }
  return candidate;
}

改进binarySearchLeftmost1,让它返回更有用的值

public static int binarySearchLeftmost2(int[] a,int target){
  int i=0;
  int j=a.length-1;
  while(i<=j){
    int m=(i+j)>>>1;
    if(target<=a[m]){
      j=m-1;
    }else{
      i=m+1;
    }
  }
  //返回大于等于目标的最靠左索引
  return j;
}
posted @ 2024-01-31 10:55  狗狗没有坏心眼  阅读(6)  评论(0编辑  收藏  举报