基础二分查找详细分析(Java实现)

定义

二分查找,也叫折半查找,是一种在有序数组中查找目标值的算法。它通过将待查找区间不断二分,在每一次比较中逐步缩小待查找范围,最终找到目标值或者确定其不存在。

力扣练习

35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。
示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2
示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1
示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

提示:
nums 为 无重复元素 的 升序 排列数组

思路分析:(这里给出两种常用思路)
题目要求我们找到第一个大于或等于目标值的索引

第一种思路:以left<=right为循环条件

class Solution {
    public int searchInsert(int[] nums, int target) {
        int l = 0;
        int r = nums.length - 1;
        int mid;
        while(l <= r){
            mid = l + (r - l) / 2;
            if(nums[mid] < target){
                l = mid + 1;
            }else{
                r = mid - 1;//right以右一定大于或等于target,循环结束后left一定等于right+1
            }               //所以left即为满足题目要求的索引
        }
        return l;
    }
}

第二种思路(力扣高赞思路):以left<right为循环条件(但是这种情况必须进行一个特殊判断,比如1 3 5 6 插入7,如果没有这个判断那么返回的索引为3而不是4,如果插入0那结果正确,不易理解因此建议优先选择第一种思路)(答主以后彻底悟了再回来修改…)

class Solution {
    public int searchInsert(int[] nums, int target) {
        int len = nums.length;
        // 特殊判断
        if (nums[len - 1] < target) {
            return len;
        }
        int l = 0;
        int r = nums.length - 1;
        int mid;
        while(l < r){
            mid = l + (r - l) / 2;
            if(nums[mid] < target){
                l = mid + 1;
            }else{
                r = mid;//从right开始以右一定大于或等于target,循环结束后left一定等于right
            }           //所以left或right为第一个大于等于target的数,即为满足题目要求的索引
        }
        return l;
    }
}

(力扣评论)二分法查找,如果存在目标值,直接返回
否则一直搜索,最后返回leftindex。
因为如果最后mid大于目标值,right为mid-1,此时插入位置为left;如果mid小于目标值,left为mid+1,此时插入位置为left。

(力扣评论)根据if的判断条件,left左边的值一直保持小于target,right右边的值一直保持大于等于target,而且left最终一定等于right+1,这么一来,循环结束后,在left和right之间画一条竖线,恰好可以把数组分为两部分:left左边的部分和right右边的部分,而且left左边的部分全部小于target,并以right结尾;right右边的部分全部大于等于target,并以left为首。所以最终答案一定在left的位置。(个人认为理解起来最清晰易懂,也是第一种思路的解释)

注意:二分查找适用于有序数组(或者有序列表)中查找目标值的情况。因为在无序的数据结构中,无法保证比较区间的大小和方向,从而无法利用二分查找的优势,需要使用其他类型的查找算法。

69. x 的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
示例 1:

输入:x = 4
输出:2
示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。

class Solution {
    public int mySqrt(int x) {
        int l = 0;
        int r = x;
        int mid,ans = -1;
        while(l <= r){
            mid = l + (r - l) / 2;
            if((long)mid * mid <= x){
                ans = mid;
                l = mid + 1;
            }else{
                r = mid - 1;
            }
        }
        return ans;
    }
}

思路分析:
由于x平方根的整数部分ans是满足 k2 ≤ x 的最大 k 值,只要mid <= x/mid,left左边界就会一直向右移动,ans就会一直更新(变大),直到不在满足mid * mid <= x的条件为止,ans就会停止更新,永远停在满足 mid * mid <= x 条件下面的最后一次更新,即满足ans * ans <= mid的最大值。
二分查找的下界为 0,上界可以粗略地设定为 x。在二分查找的每一步中,我们只需要比较中间元素 mid 的平方与 x 的大小关系,并通过比较的结果调整上下界的范围。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值