算法基础入门 - 4、二分算法

本文详细介绍了二分算法的基本思想和时间复杂度,并通过三个实例展示了二分算法在有序数组中的应用:查找目标值的存在、寻找大于等于目标值的最左侧位置以及在无序数组中寻找局部最小值。每个实例都提供了具体的解题思路和代码实现,进一步阐述了二分算法的灵活性和实用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4、二分算法

主要思想:每次查询都能缩减一半的范围
时间复杂度:O(log n) ; 空间复杂度O(1):

首先的一个问题:是不是只有排好序的元素才能使用二分算法?

下面的第三道算法题会回答这个问题!

1、在一个有序数组中找某个数是否存在

经典二分算法,无需查找至最后一个值。遍历过程中如果发现了target,直接返回。

解题思路:
1、因为是有序数组,直接找中点下标mid
2、若arr[mid] 比我们的目标值大,说明我们的目标值在[0, mid-1]区间
3、若arr[mid] 比我们的目标值小,说明我们的目标值在[mid+1, length]区间
4、每次判断都可将数据范围缩减一半,最终可得结果

public int binarySearch(int[] arr, int target) {
    int left = 0,right = arr.length-1;
    int result = 0;

    while(left < right) {
        //这种求中点的方式可以防止整数溢出
        int mid = left + ((right - left) >> 1);

        if(arr[mid] > target) {
            right = mid-1;
            continue;
        }
        if(arr[mid] < target) {
            left = mid + 1;
            continue;
        }

        result = mid;
        break;
    }

    return result;
}

2、在一个有序数组中,查找>=某个数的 最左侧的位置

特殊的二分算法,涉及到范围判断,必须查找到最后一个值,才能判断出答案。

解题思路:
1、因为是有序数组,直接找中点下标mid
2、若arr[mid] >= target,说明我们的目标值在[0, mid]区间
3、若arr[mid] < target,说明我们的目标值在[mid+1, length]区间
4、每次判断都可将数据范围缩减一半,最终可得结果

public int rangeBinarySearch(int[] arr, int target) {
    int left = 0,right = arr.length-1;
        while(left < right) {
            int mid = left + ((right-left) >> 1);
            if(arr[mid] >= target) {
                right = mid;
            } else {
                left = mid+1;
            }
        }
        return left;
}

3、在一个无序数组中,求一个局部最小值

特殊情况下的二分: 无序
解决算法问题思路:1、数据是否特殊;2、限定条件是否特殊;

局部最小定义:i下标的元素,既比i-1下标的元素值小,又比i+1下标的元素值小,则可称之为局部最小;(开头的元素和结尾的元素比较特殊,只有一侧有元素,只需要保证比这一侧的元素小即可)
5 3 3 1 1 6 4 4 8 其中1和4都是局部最小值

解题思路:
1、若两端的元素都不是局部最小值,那么这两个数中间肯定有一个(或多个)低点(局部最小值);
2、取中点,假设中点也不是局部最小值,那么[0, mid) 或者[mid, length] ,这两个区间肯定都有一个或多个低点。
3、假设每次都取[0, mid)
4、每次判断都可将数据范围缩减一半,最终肯定有一次是mid下标即为局部最小值。

public int partMinBinarySearch(int[] arr) {
    int left = 0,right = arr.length-1;
    
    //首先判断两个特殊情况
    if(arr[left] < arr[left+1]) {
        return arr[0];
    }
    if(arr[right] < arr[right-1]) {
        return arr[right];
    }
    
    int result = -1;
    while(left < right) {
        int mid = left + ((right-left) >> 1);
        if(isPartMin(arr, mid)) {
            result = arr[mid];
            break;
        } else {
            right = mid - 1;
        }
    }
    return result;
}

private boolean isPartMin(int[] arr, int index) {
    return arr[index] <= arr[index-1] && arr[index] <= arr[index+1];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值