二分法

本文深入解析二分法的基本原理及其在程序设计中的应用,通过具体实例讲解如何使用二分法查找数组中的元素,特别关注边界条件的处理。同时,文章详细分析了一道复杂度为O(logn)的力扣题目,展示了如何利用二分法寻找目标值的起始和结束位置。

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

二分法

数学中的二分法我们都学过,但是运用到这我就忘了,程序中的二分法是起源于数学中的函数找零点,假设待查找序列和题目的要求之间的关系是单调递增的,先取区间的中心,判断该处函数值和题目标准值的大小关系,如果函数值偏小,那么应该在中心右侧的区间继续查找;如果函数值偏大 ,那么应该在中心左侧区间继续查找,直到找到对应的值或者区间缩小到左右端点之间不再包含其他数据结束。
这样一段代码:我们都能看懂什么意思,但是里面的每一个临界点(4个推敲点)才是我们需要去推敲的

public static int rank(int key,int nums[])//nums必须有序
{
    //查找范围的上下界
    int low=0;
    int high=nums.length-1;
    //未查找到的返回值
    int notFind=-1;
    while(low<=high)
    {
        //二分中点=数组左边界+(右边界-左边界)/2
        //整数类型默认取下整
        int mid=low+(high-low)/2;
       if(nums[mid==key])
        {
            //查找成功
            return mid;
        }
        //中间值是如果大于key
        else if(nums[mid]>key)//推敲点1
        {
            //证明key在[low,mid-1]这个区间
            //因为num[mid]已经判断过了所以下界要减一
            high=mid-1;//推敲点2
        }
        else if(nums[mid]<key)//推敲点3
        {
            //证明key在[mid+1,high]这个区间
            //同样判断过mid对应的值要从mid+1往后判断
            low=mid+1;//推敲点4
        }
    }
    //while循环完了都没返回,肯定没找到咯
    return notFind;
}

力扣34
题目:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

你的算法时间复杂度必须是 O(log n) 级别。

如果数组中不存在目标值,返回 [-1, -1]。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

**分析:**这道题的要求有复杂度限制,显然是需要用二分法去求解的,二分法找一个数想必我们都陌生了,需要注意的是关于边界值的取舍。只找到一个数的话,找到我们就可以返回了,但是这道题不是,当我们找到一个数时,我们得确定他的左边和右边都没有相同的数才能最后返回。因此我们得进行左边搜索最小索引和右边搜索最大索引。

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ans={-1,-1};
        ans[0]=findFirst(nums,target);
        ans[1]=findLast(nums,target);
        return ans;
        
    }
static int findFirst(int[] nums, int target) {
        if (nums.length == 0) return -1;
        int first = 0;
        int last = nums.length; // 注意
        while (first < last) { // 注意
            int mid = (first + last) / 2;
            if (nums[mid] == target) {
                last = mid;
            } else if (nums[mid] < target) {
                first = mid + 1;
            } else if (nums[mid] > target) {
                last = mid; // 注意
            }
        }
        // target 比所有数都大
        if (first == nums.length) return -1;
        // 如果最后找到了最小的目标返回目标的位置,没有返回-1
        return nums[first] == target ? first : -1;

    }
    static int findLast(int[] nums, int target) {
        if (nums.length == 0) return -1;
        int first = 0, last = nums.length;
        while (first < last) {
            int mid = (first + last) / 2;
            if (nums[mid] == target) {
                first = mid + 1; // 注意
            } else if (nums[mid] < target) {
                first = mid + 1;
            } else if (nums[mid] > target) {
                last = mid;
            }
        }
        //target比所有数都小
        if (first == 0) return -1;
        // 如果最后找到了最大的目标返回目标的位置,没有返回-1
        return nums[first -1] == target ? (first -1) : -1;
    }
}
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值