Leetcode 704 二分查找

Leetcode 704 二分查找

题目描述:

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

示例1:

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

示例2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

代码:

class Solution:

  def search(self, nums: List[int], target: int) -> int:

​    low,high=0,len(nums)-1while low<=high:

​      mid=(high-low)//2+low

​      num=nums[mid]if num==target:return mid

​      elif num>target:

​        high=mid-1else:

​        low=mid+1return -1

关于二分查找的思考:

这是一道典型的二分查找题,由题目所述,给定的输入数组nums是有序的,我们需要从中查找一个给定的target值,当然,逐个遍历不妨是一种方法,但是时间过长,不推荐采用。
这里我们可以通过寻找low与high的中间值mid,并将其与要查找的target进行对比,如果nums[mid]==target,那么一次就可以找到,并且时间复杂度为O(1),如若不相等,则可以通过比较nums[mid]与target的大小,近一步改变相应的low,high的值(若num>target,则high=mid-1;若num<target,则high=low+1),逐步缩小查找的范围,直至找到target,输出其下标。
下面,讲一讲二分查找。

什么是二分查找?

二分查找是计算机科学中最基本,最有用的算法之一,它描述了再有序集合中搜索特定值的过程,是一种在有序数组中查找特定元素的搜索算法。

二分查找中使用的术语:

目标target——要查找的值

索引index——要查找的当前位置

左、右指示符Left、Right——用来维持查找空间的指标

中间指示符mid——用以确定下一步是向左查找还是向右查找

用于二分查找的代码大同小异,整体都差不多,重点就在于边界条件的处理,到底是 while(left < right) 还是 while(left <= right),到底是right = middle呢,还是要right = middle - 1呢?

下面介绍两个模板(具有重复元素的数组也可以使用):

模板一:
int lower_bound(int* nums, int numsSize, int target){ 
 int left = 0;                                          
 int right = numsSize-1;                              
 while(left < right){ # 搜索区间左闭右开[first, last)不为空  
    #防溢出                                                  
    int mid = left + right >> 1;    
    if(nums[mid] >= target) right = mid; 
    else left = mid + 1;
} 
return left;   // right也行,因为[left, right)为空的时候它们重合 }

mid=(left+right)>>1的含义:

右移运算符>>,运算结果正好能对应一个整数的二分之一值,正好能代替数学上的除2运算,但是比除2运算要快。

mid=(left+right)>>1相当于mid=(left+right)/2

如果中点大于等于 target,表示目标在左侧,数组范围应该从 [left, right] 变成 [left, mid],否则,就从 [left, right] 变成 [mid+1, right]

模板二:
int lower_bound(int* nums, int numsSize, int target){ 
 int left = 0; 
 int right = numsSize-1;
 while(left < right){ # 搜索区间[first, last)不为空 
   # 防溢出  
   int mid = left + right + 1 >> 1; # 防止死循环,mid加1      
   if(nums[mid] <= target)
        left = mid; 
   else right = mid - 1;
}                                                     
return right;   # right也行,因为[left, right)为空的时候它们重合 }

如果中点小于等于 target,表示目标在右侧,数组范围应该从 [left, right] 变成 [mid, right],否则,就从 [left, right] 变成 [left, mid+1]

总结:

模板一:mid=(left+right)/2,if条件判断(nums[mid]>=target),区间 [left, right] 划分成 [left, mid][mid + 1, right] 时,其更新操作是 right = mid 或者 left = mid + 1;,计算 mid 时不需要加 1,更适用于寻找二分的左边界。

模板二:mid=((left+right)/2)+1,if条件判断(nums[mid]<=target),区间 [left, right] 划分成 [left, mid - 1][mid, right] 时,其更新操作是 r = mid - 1 或者 l = mid;,此时为了防止死循环,计算 mid 时需要加 1,更适用于寻找二分的右边界。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周泡泡同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值