二分法查找Binary Search

1. 二分法查找算法,判断一个数是否在一个有序数组中存在,最快的方法就是二分法,时间复杂度为O(Logn)

2. 利用二分思想,每次与中间数值比较,缩小查找范围。

3. 写好二分查找需要注意,循环条件是low <= high; mid取值最好不用mid=(low+high)/2, 而是用low + ((high-low) >>1),位运算效率高,且避免溢出。

应用:

a. 查找第一个(最后一个)值等于给定值的元素,数组可能存在重复的元素。对于我们做工程的人来说,代码易懂,bug free,其实最重要。

public int bsearch(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;
  while (low <= high) {
    int mid =  low + ((high - low) >> 1);
    if (a[mid] > value) {
      high = mid - 1;
    } else if (a[mid] < value) {
      low = mid + 1;
    } else {
      if ((mid == 0) || (a[mid - 1] != value)) return mid; // 第一个
    // if ((mid == n - 1) || (a[mid + 1] != value)) return mid; //最后一个
else high = mid - 1; } } return -1; }

b. 查找第一个大于等于给定值的元素 / 查找最后一个小于等于给定值的元素

public int bsearch(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;
  while (low <= high) {
    int mid =  low + ((high - low) >> 1);
    if (a[mid] >= value) {
      if ((mid == 0) || (a[mid - 1] < value)) return mid;
      else high = mid - 1;
    } else {
      low = mid + 1;
    }
  }
  return -1;
}
public int bsearch(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;
  while (low <= high) {
    int mid =  low + ((high - low) >> 1);
    if (a[mid] > value) {
      high = mid - 1;
    } else {
      if ((mid == n - 1) || (a[mid + 1] > value)) return mid;
      else low = mid + 1;
    }
  }
  return -1;
}

c.根据一个IP地址查询归属地,ip地址是可以转换为一个数值的, 把原来的区间起始地址构造成一个有序数组,然后对应查找最后一个最后一个小于等于给定值的元素,找到后在到对应区间去看是否在区间内,在则显示,不在就显示未找到。

d.求平方根

class Solution {
    public int mySqrt(int x) {
        int l = 0, r = x, ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if ((long)mid * mid <= x) {
                ans = mid;
                l = mid + 1;
            }
            else {
                r = mid - 1;
            }
        }
        return ans;
    }
}

 

e.二分查找的优势在于近似查找,存在重复元素,这是散列表和二叉查找树没法实现的。

posted @ 2020-08-22 11:58  lswtianliang  阅读(207)  评论(0编辑  收藏  举报