算法-二分法

序:二分法使用场景中,数位未必一定有序;只要能够构建排他性,就可使用二分法(可以砍掉左侧或者右侧)

适用场景:

1.在一个有序数组中,找到某个数是否存在

2.在一个有序数组中,找>=某个数的最左位置(例:【1,2,4,4,4,7,8,9】找4的最左位置。答案:2位置)

3.在一个有序数组中,找<=某个数的最右位置

4.局部最小问题


有序数组中,找某个数是否存在

public class SearchNum {

    public boolean exist(int[] target, int num) {
        boolean result = false;
        if (target == null || target.length < 1) {
            return result;
        }

        int left = 0, right = target.length - 1, mid = 0;

        while (left < right) {
            //(left + right) / 2 可能溢出 left = 19亿 right = 20亿,相加后溢出
            mid = left + ((right - left) >> 1);

            if (target[mid] == num) {
                result = true;
                return result;
            } else if (target[mid] > num) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

        result = target[left] == num;

        return result;
    }
}

有序数组中,找>=某个数的最左位置

public class SearchLeftmost {

    public Integer search(int[] target, int num) {
        Integer result = null;
        if (target == null || target.length < 1) {
            return result;
        }

        int left = 0, right = target.length - 1, mid = 0;

        while (left <= right) {
            //(left + right) / 2 可能溢出 left = 19亿 right = 20亿,相加后溢出
            mid = left + ((right - left) >> 1);

            if (target[mid] >= num) {
                right = mid - 1;
                result = mid;
            } else {
                left = mid + 1;
            }

        }

        return result;

    }
}

局部最小问题:

题目:

无序数组,任意相邻的俩个数不等,数组中的数可以是负数,正数,0。求局部最小(找到一个局部最小位置即可)
备注-局部最小的口径如下
a.0位置的数比1位置的数小,那么0是局部最小
b.n-1位置的数比n-2位置的数小,那么n-1是局部最小
c.中间的数(非0位置,非n-1),比它左面的数小且比它右面的数小,那么次数的位置是局部最小

思想:二分法

证明二分法的可行性:

a.校验数组0位置的数是否小于1位置,如果小于,返回0

b.校验数组n-1位置的数是否小于n-2位置的,如果小于,返回n-1

c.如果a和b都不成立,说明0位置与1位置组成的局部是递减的且n-2位置和n-1位置组成的局部是递增的。综上证明“中间一定有局部最小的存在”

d.找到中间位置mid,判断中间位置的值是否比mid-1且比mid+1小,如果以上成立,那么返回mid位置;但如果不成立,出现如下情况

要么mid比mid-1大(砍掉右侧,左侧必存才局部最小)

 

要么mid比m+1大(砍掉左侧,右侧必存才局部最小)

要么mid大于mid-1且大于mid+1(左侧,右侧均可)

代码:

public class LocalMin {

    public int searchLocalMin(int[] target) {
        int result = -1;
        if (target == null || target.length <= 1) {
            return result;
        }

        int left = 0, right = length, mid = 0;
        if (target[left] < target[left + 1]) {
            result = 0;
            return result;
        }

        if (target[right] < target[right - 1]) {
            result = right;
            return result;
        }

        left ++;
        right --;
        while (left < right) {
            mid = left + ((right - left) >> 1);

            if (target[mid] > target[mid - 1]) {
                right = mid - 1;
            } else if (target[mid] > target[mid + 1]) {
                left = mid + 1;
            } else {
                result = mid;
                return result;
            }
        }

        result = left;

        return result;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值