二分查找算法延伸

需求:给定一个数组,一个目标值。在数组中查找不大于目标值且下标最大的值、不小于目标值且下标最小的值。

/**
 * 二分查找
 */
public class BinarySearch {

    /**
     * 找出不小于目标值的最小下标
     *
     * @param array 数组
     * @param target 目标值
     * @param index 与目标值最接近的值下标
     * @return int
     */
    public int getLowerBound(int[] array, int target, int index) {
        if (array[0] >= target) {
            return 0;
        }
        if (array[array.length - 1] < target) {
            return -1;
        }

        int idx = index;
        if (array[index] < target) {
            while (array[idx] == array[idx + 1]) {
                idx++;
            }
            idx++;
        } else {
            while (array[idx] == array[idx - 1]) {
                idx--;
            }
        }
        return idx;
    }

    /**
     * 找出不大于目标值的最大下标
     *
     * @param array 数组
     * @param target 目标值
     * @param index 与目标值最接近的值下标
     * @return int
     */
    public int getUpperBound(int[] array, int target, int index) {
        if (array[0] > target) {
            return -1;
        }

        if (array[array.length - 1] <= target) {
            return index;
        }

        int idx = index;
        if (array[index] > target) {
            while (array[idx] == array[idx - 1]) {
                idx--;
            }
            idx--;
        } else {
            while (array[idx] == array[idx + 1]) {
                idx++;
            }
        }
        return idx;
    }

    /**
     * 二分查找与目标值最接近的值
     *
     * @param array 数组
     * @param target 目标值
     * @return int
     */
    public int search(int[] array, int target) {

        if (array.length < 1) {
            return -1;
        }
        if (array.length == 1) {
            return 0;
        }

        int middle = 0;
        int low = 0, high = array.length - 1;
        if (target <= array[0]) {
            return 0;
        } else if (target >= array[array.length - 1]) {
            return array.length - 1;
        }

        while (low < high) {
            middle = (low + high) / 2;
            if (Math.abs(array[middle + 1] - target) > Math.abs(array[middle] - target)) {
                high = middle;
            } else if (Math.abs(array[middle + 1] - target) < Math.abs(array[middle] - target)) {
                low = middle + 1;
            } else { // 相等的情况
                if (array[middle + 1] >= target) {
                    high = middle;
                } else {
                    low = middle + 1;
                }
            }
        }
        return Math.abs(array[middle + 1] - target) > Math.abs(array[middle] - target) ? middle : middle + 1;
    }

    @Test
    public void test01() {
        int[] array = {2, 2, 2, 5, 7, 20, 30, 30, 30, 32, 32, 32, 36, 36, 120, 123, 500, 500, 500};
        int val = 30;
        int lowerBound = getLowerBound(array, val, search(array, val));
        int upperBound = getUpperBound(array, val, search(array, val));
        assertEquals(6, lowerBound);
        assertEquals(8, upperBound);

        val = 32;
        lowerBound = getLowerBound(array, val, search(array, val));
        upperBound = getUpperBound(array, val, search(array, val));
        assertEquals(9, lowerBound);
        assertEquals(11, upperBound);

        val = 1;
        lowerBound = getLowerBound(array, val, search(array, val));
        upperBound = getUpperBound(array, val, search(array, val));
        assertEquals(0, lowerBound);
        assertEquals(-1, upperBound);

        val = 510;
        lowerBound = getLowerBound(array, val, search(array, val));
        upperBound = getUpperBound(array, val, search(array, val));
        assertEquals(-1, lowerBound);
        assertEquals(18, upperBound);

        val = 120;
        lowerBound = getLowerBound(array, val, search(array, val));
        upperBound = getUpperBound(array, val, search(array, val));
        assertEquals(14, lowerBound);
        assertEquals(14, upperBound);

        val = 2;
        lowerBound = getLowerBound(array, val, search(array, val));
        upperBound = getUpperBound(array, val, search(array, val));
        assertEquals(0, lowerBound);
        assertEquals(2, upperBound);


        val = 500;
        lowerBound = getLowerBound(array, val, search(array, val));
        upperBound = getUpperBound(array, val, search(array, val));
        assertEquals(16, lowerBound);
        assertEquals(18, upperBound);

        int[] vals = {30, 32, 1, 510, 120 , 2, 500};
        int[] expectLowBound = {6, 9, 0, -1, 14, 0, 16};
        int[] expectUpperBound = {8, 11, -1, 18, 14, 2, 18};

        for (int i = 0; i < vals.length; i++) {
            assertEquals(expectLowBound[i], getLowerBound(array, vals[i], search(array, vals[i])));
            assertEquals(expectUpperBound[i], getUpperBound(array, vals[i], search(array, vals[i])));
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东心十

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值