03_二分法

二分法

认识二分法

经常见到的类型是在一个有序数组上,开展二分搜索

但有序真的是所有问题求解时使用二分的必要条件吗?

只要能正确构建左右两侧的淘汰逻辑,你就可以二分(排他性)


二分查找

存在性

普通逻辑

public class BSExist {
    public static boolean exist(int[] sortedArr, int num) {
        if (sortedArr == null || sortedArr.length == 0) return false;
        int L = 0, R = sortedArr.length - 1, mid;
        while (L <= R) {
            mid = L + ((R - L) >> 1);
            if (sortedArr[mid] == num) return true;
            else if (sortedArr[mid] < num) R = mid - 1;
            else L = mid + 1;
        }
        return false;
    }
}

补丁版

public class BSExistAnother {
    public static boolean exist(int[] sortedArr, int num) {
        if (sortedArr == null || sortedArr.length == 0) return false;
        int L = 0, R = sortedArr.length - 1, mid;
        while (L < R) {
            mid = L + ((R - L) >> 1);
            if (sortedArr[mid] < num) L = mid + 1;
            else if (sortedArr[mid] > num) R = mid - 1;
            else return true;
        }
        return sortedArr[L] == num;
    }
}

不等查找

大于等于某个值最左侧的位置

public class BSNearLeft {
    public static int nearestIndex(int[] sortedArr, int value) {
        if (sortedArr == null || sortedArr.length == 0) return -1;
        int L = 0;
        int R = sortedArr.length - 1;
        int index = -1;
        int mid;
        while (L <= R) {
            mid = L + ((R - L) >> 1);
            if (sortedArr[mid] >= value) {
                index = mid;
                R = mid - 1;
            } else {
                L = mid + 1;
            }
        }
        return index;
    }
}

小于等于某个值最右侧的位置

public class BSNearRight {
    public static int nearestIndex(int[] sortedArr, int value) {
        if (sortedArr == null || sortedArr.length == 0) return -1;
        int L = 0;
        int R = sortedArr.length - 1;
        int index = -1;
        int mid;
        while (L <= R) {
            mid = L + ((R -L) >> 1);
            if (sortedArr[mid] <= value) {
                index = mid;
                L = mid + 1;
            } else {
                R = mid - 1;
            }
        }
        return index;
    }
}

局部最小值

1.无序数组中任意两个相邻的数都不相等
2.如果边界点比旁边的数小,是局部最小值

public class BSAwesome {
    public static int getLessIndex(int[] array) {
        if (array == null || array.length == 0) return -1;
        // 如果0位置的数是局部最小,则马上返回0位置
        // 如果0位置的数不是局部最小,则在0位置的趋势是局部向下的
        if (array.length == 1 || array[0] < array[1]) return 0;
        // 如果n-1位置是局部最小,则马上返回n-1位置,不用后续过程
        // 如果n-1位置不是局部最小,则在n-2到n-1位置的趋势是局部向上的
        if (array[array.length - 1] < array[array.length - 2]) return array.length - 1;
        // 如果上面两个都不是局部最小,说明整个数组的趋势是先往下再往上的
        // 中间必存在一个局部最小
        int left = 1;
        int right = array.length - 2;
        int mid;
        while (left < right) {
            // 直接来到中点位置
            mid = left + ((right - left) >> 1);
            // mid有可能比左边大,有可能比右边大,有可能都大
            // 设定规则,都大的时候区间往左边缩小
            if (array[mid] > array[mid-1]) right = mid - 1;
            else if (array[mid] > array[mid + 1]) left = mid + 1;
            // 如果mid是局部最小,直接返回
            else return mid;
        }
        return left;
    }
}

posted @ 2021-03-05 13:36  Aokigahara  阅读(68)  评论(0编辑  收藏  举报