二分法学习笔记第一版

二分法学习笔记第一版

1. 理论知识

  • 二分法可以变成一棵高度优化的二叉搜索树,适用条件

    数据有序

    支持随机访问

2. 应用场景

  • 二分搜索常常用于优化暴力搜索,快速求解,时间复杂度是O(logn)

3.二分算法常见的三种类型

  • 搜索特定值
/**
     * 子有序表中搜索target对应的下标,若不存在,则返回-1;
     * @param arr 升序数组
     * @param target
     * @return
     */

public static int SerachSpeValue(int[] arr, int target){
    int low = 0, high = arr.length - 1, mid;
    while(low <= high){
        mid = low + (high - low) / 2; // 防止溢出
        if (arr[mid] == target)return mid;
        else if (arr[mid] < target)low = mid + 1;
        else high = mid - 1;
    }
    return -1;
}

watch out! 左边下标是length - 1 ,即指向最后一个元素。所一while循环必须是low <= high ,不能是low < high。当low == high 时,这个时候不能退出循环,必须还要查找一次。

  • 搜索数组中大于等于某个特定值的数
/**
     * 搜索第一个大于等于target的值
     * @param arr 升序数组
     * @param target
     * @return
     */
    public static int SearchFirstGreaterOrEqualTarget(int[] arr, int target){
        int low = 0, length = arr.length, high = length, mid; // 注意high是length ,不是length - 1
        while(low < high){ // <= 可能会造成死循环
            mid = low + (high - low) / 2;
            if (arr[mid] < target)low = mid + 1;   // 大于等于的数一定在mid后面
            else high = mid;                  // mid对应的数字有可能是第一个大于等于target的,也有可能是不是,需要缩小。
        }
        if (high == length)return -1; // 不存在的话,high = length
        return high;   // high对应第一个大于等于的数字
    }

**这里high变成了length, 指向数组最后元素的下一个位置,所以呢,while循环不可以取等号。极易产生死循环,通过模拟可以知道,最后返回值的下标为high,但是要考虑到如果这样的值不存在咋办,不存在时high为数组长度,所以最后判断以下即可
***
  • 搜索数组中小于某个特定值的数

这题的代码其实就是搜索数组中大于等于某个特定值的数的变形。最后返回结果的下标变成high-1就可以了。

/**
     * 搜索第一个小于的数字,就是搜索第一个大于等于target的值的变体,修改下搜索不到的条件
     * if (arr[0] >= target)return -1;
     * 退出后返回high - 1;
     */

    public static int SearchLastLessTarget(int[] arr, int target){
        int low = 0, length = arr.length, high = length, mid;
        while(low < high){ // <= 会造成死循环
            mid = low + (high - low) / 2;
            if (arr[mid] < target)low = mid + 1;   // 大于等于的数一定在mid后面
            else high = mid;                  // mid对应的数字有可能是第一个大于等于target的,也有可能是不是,需要缩小。
        }
        if (high == 0)return high - 1; // 不存在的话,high = 0 ,则返回-1
        return high - 1;   // high对应第一个大于等于的数字,没有返回length,减一后必然小于target。
    }

**这里注意一下,如果最发现不存在这样的数字,high指向0,所以减一后就返回-1了,也可以把return前面的if判断给删了。

  • 搜索数组中大于某个特定值的数
/**
     * 搜索第一个大于target的值的下标,不存在则返回-1
     * @param arr 升序数组
     * @param target
     * @return
     */
    public static int SearchFirstGreaterTarget(int[] arr, int target){
        int low = 0, length = arr.length, high = length, mid;
        while(low < high){ // <= 会造成死循环
            mid = low + (high - low) / 2;
            if (arr[mid] <= target)low = mid + 1;   // 大于target的数一定在mid后面
            else high = mid;                  // mid对应的数字有可能是第一个大于target的,也有可能是不是,需要缩小。
        }
        if (high == length)return -1;
        return high;
    }
  • 搜索数组中小于等于某个特定值的数
/**
     * 搜索第一个小于等于target的数字,就是搜索第一个大于target的值的变体,修改下搜索不到的条件
     * if (arr[0] > target)return -1;
     * 退出后返回high - 1;
     */
    public static int SearchLastLessOrEqualTarget(int[] arr, int target){
        int low = 0, length = arr.length, high = length, mid;
        while(low < high){ // <= 会造成死循环
            mid = low + (high - low) / 2;
            if (arr[mid] <= target)low = mid + 1;   // 大于target的数一定在mid后面
            else high = mid;                  // mid对应的数字有可能是第一个大于target的,也有可能是不是,需要缩小。
        }
        // if (high == 0)return high - 1; 和下一句合并
        return high - 1;
    }
posted @ 2020-08-28 21:42  FizzPu  阅读(150)  评论(0编辑  收藏  举报