LeetCode704——二分查找

二分查找:逐步缩小搜索区间

使用场景:

1.数组为有序排列

2.数组中没有重复元素


题目:力扣704题

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

解题思路:

1.理解题意:

由题意得:

数组的特点:有序,升序,整型

分析如下四种情况,最后两种情况相似,可以看成一种:

方式一:目标值在数组中

方式二:目标值不在数组中,目标值位于数组中两个相邻值之间

方式三:目标值不在数组中,且目标值大于数组中所有的值

方式三:目标值不在数组中,且目标值小于数组中所有的值

2.解题方法

2.1定义两个指针,left和right

left为数组最左侧的边界(也是起始索引):一般开始为0

left = 0;

right为数组最右侧的边界(末端索引):一般由数组长度(nums.length)决定

right = nums.length - 1;
2.2while 循环判断
2.2.1当 left <=right时,执行以下步骤:

区间范围:[left,right]

2.2.1.1上述区间范围里,中间值的中间索引:

该算法防止出现溢出现象:

int middle =  left + (right - left)/2;
2.2.1.2判断目标值所在的区间:

①当目标值与数组中索引为middle的值相等时:

nums[middle] = target

便在数组中找到了这个数,返回其索引即可:

return middle;

②当目标值小于数组中索引为middle的值时:

nums[middle] > target

我们就可以得出结论:

目标值target < nums[middle]

此时我们需要向左继续缩小目标值的区间:

缩小区间的范围为:[left,middle)

因为while循环的条件要求left要小于等于right,

左边界不变,

右边界:

right =middle - 1;

所以区间的范围就要修改为:[left,right]

③当目标值大于数组中索引为middle的值时:

nums[middle] < target

我们就可以得出结论:

目标值target > nums[middle]

此时我们需要向右继续缩小目标值的区间:

缩小区间的范围为:(middle,right]

因为while循环的条件要求left要小于等于right,

右边界不变,

左边界:

left =middle + 1;

所以区间的范围就要修改为:[left,right]

2.2.1.3继续执行2.2.1.1的步骤
2.2.1.4如果当left=right时,nums[middle]不等于target,说明数组中没有该值
2.2.1.5当left>right时,退出while循环,返回-1
2.3数字代入:

方式一:

索引index =	  0	  1   2   3   4   5
数组nums:  	[-1	, 0 , 3 , 5 , 9 , 12]
目标值target =9

① left =0		right =5
区间范围:[0,5]
left<right
middle =left+(right-left)/2=2
nums[2] =3<target
可知:目标值在索引为2的值的右边
向右缩小区间范围:即区间的左边界向右移动
left =middle+1=3
区间范围:[3,5]

②left =3 	right =5
left<right
middle =left+(right-left)/2=4
nums[4] =target=9
在数组中找到目标值:
返回索引middle =2

方式二:

索引index =	  0	  1   2   3   4   5
数组nums:  	[-1	, 0 , 3 , 5 , 9 , 12]
目标值target =2

① left =0		right =5
区间范围:[0,5]
left<right
middle =left+(right-left)/2 =2
nums[2] =3>target
可知:目标值在索引为2的值的左边
向左缩小区间范围:即区间的右边界向左移动
right = middle-1=1
区间范围:[0,1]

②left = 0 	right = 1
left<right
middle =left+(right-left)/2=0
nums[0] =-1<target
可知:目标值在索引为0的值的右边
向右缩小区间范围:即区间的左边界向右移动
left = middle+1=1
区间范围:[1,1]

left = 1	right = 1
left = right
middle =left+(right-left)/2=1
nums[1]=0<target
可知:目标值在索引为1的值的右边
向右缩小区间范围:即区间的左边界向右移动
left = middle+1=2
区间范围:[2,1]
此时left>right,退出循环
在数组中没有找到目标值:返回-1

方式三和方式四类似:此处以方式三为例:

索引index =	  0	  1   2   3   4   5
数组nums:  	[-1	, 0 , 3 , 5 , 9 , 12]
目标值target =13

① left =0		right =5
区间范围:[0,5]
left<right
middle =left+(right-left)/2 =2
nums[2] =3<target
可知:目标值在索引为2的值的右边
向左缩小区间范围:即区间的左边界向右移动
left = middle+1=3
区间范围:[3,5]

②left = 3 	right = 5
left<right
middle =left+(right-left)/2=4
nums[4] =9<target
可知:目标值在索引为4的值的右边
向右缩小区间范围:即区间的左边界向右移动
left = middle+1=4
区间范围:[4,5]

left = 4	right = 5
left<right
middle =left+(right-left)/2=4
nums[4]=9<target
可知:目标值在索引为4的值的右边
向右缩小区间范围:即区间的左边界向右移动
left = middle+1=5
区间范围:[5,5]

left = 5	right = 5
reft = right 
middle =left+(right-left)/2=5
nums[5]=12<target
可知:目标值在索引为5的值的右边
向右缩小区间范围:即区间的左边界向右移动
left = middle+1=6
区间范围:[6,5]
此时left>right,退出循环
在数组中没有找到目标值:返回-1
代码:
class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while(right >= left){
            int middle = left + (right - left)/2;
            if(nums[middle] == target){
                return middle;
            }else if(nums[middle] > target){
                right = middle - 1;
            }else{
                left = middle + 1;
            }
        }
        return -1;
    }
}

结语:

著此篇,与君享,互勉之,共进步!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值