leetcode刷题记录(一)——704.二分查找

(一)问题描述

         leetcode题目链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/binary-search/

      给定一个 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

提示:

  • 你可以假设nums 中的所有元素是不重复的。
  • n 将在 [1, 10000]之间。
  • nums 的每个元素都将在 [-9999, 9999]之间。

(二)关键词提取

  1. 查找
  2. 有序数组
  3. 无重复元素

     满足以上条件的问题可以考虑使用二分查找(也叫二分法、折半查找)。

     该方法可以简单理解成:取有序数组中间的元素与目标值进行比较,如果恰好中间值和目标值相等,则直接输出中间元素的索引,计算结束。对于问题中的升序数组,如果目标值大于中间值,则取数组中间元素右侧的部分,反之则取左侧部分,用这部分的中间元素与目标值再次比较。循环以上操作,直到找出与目标元素相等的元素,或者排除所有可能元素,计算终止。

(三)易错点

  1. while终止条件如何设置,应该是left<=right,还是left==right(left和right是当前计算区间的左端点和右端点索引值)
  2. 参与计算的部分变化时,right等于middle还是middle-1/left等于middle还是middle+1(middle是当前计算区间的中间位置元素索引)

(四)解题思路

      回避以上易错点的关键在于:确定每次计算的区间。一般采用左闭右闭[left,right](即每次两端的元素都参与计算)或者左闭右开[left right)(即每次左端元素参与计算,而右端元素不参与计算),至于为啥不经常用左开右闭(left,right],这个一会儿再说。

1. 左闭右闭方式

(1)while循环的条件采用left<=right。这一点看只剩下一个元素时区间是否符合闭区间的定义。

(2)每次计算区间变化时,right=middle-1/left=middle+1。因为两侧元素都参与计算,而中间位置元素刚刚已经比较过了不是要找的元素,所以要把中间元素拿掉。

伪代码:

BinarySearch ( A[0..n-1], K )

//左闭右闭的方式实现非递归的折半查找

//输入:一个升序数组 A[0..n-1] 和一个查找键K

//输出:一个数组元素的下标,该元素等于K;如果没有这样一个元素,则返回-1

left←0;right←n-1

while left<=right do

    m←⌊(left+right)/2⌋(这个符号是向下取整符号)

    if K=A[m] return m

    else if K<A[m] right←m-1

    else left←m+1 

return -1

2. 左闭右开方式

(1)起始时right不是length-1啦!右端点不参与计算,所以right应该是length!否则最后一个元素就没办法参与计算啦!这也就是为啥不经常用左开右闭,毕竟最后一个元素再“后面一个”更好表示。

(2)while循环的条件采用left<right。还是看只剩下一个元素时区间是否符合闭区间的定义。

(3)每次计算区间变化时,right=middle/left=middle+1。中间位置元素刚刚已经比较过了不是要找的元素,所以要把中间元素拿掉。计算区间取左侧一半时,右端点移动。右端点是不参与计算的,所以要正好移动到刚刚middle的位置上,如果取middle-1,那middle-1就不参与计算了,少了个元素。

伪代码:

BinarySearch ( A[0..n-1], K )

//左闭右开的方式实现非递归的折半查找

//输入:一个升序数组 A[0..n-1] 和一个查找键K

//输出:一个数组元素的下标,该元素等于K;如果没有这样一个元素,则返回-1

left←0;right←n

while left<right do

    m←⌊(left+right)/2⌋(这个符号是向下取整符号)

    if K=A[m] return m

    else if K<A[m] right←m

    else left←m+1 

return -1

(五)题解里的小知识

  1. 开头有一段判断,即如果target比数组的最小值小,比最大值大,那么就不用比了,肯定找不到,避免了多次循环计算。
 if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }

     2. 在计算下个计算区间的middle值时,采用的不是(left+right)/2的方法,而是有符号右移的方式

int mid = left + ((right - left) >> 1);

       在java语言里,整数除法是向下取整的,即直接舍掉小数部分,无论小数部分多大都舍掉,没有进1这一说。这里(right-left)>>1的写法是有符号右移一位,其实也是除以2的意思,并且也相当于向下取整。

有关移位运算符的解释icon-default.png?t=O83Ahttps://blog.csdn.net/qq_53132084/article/details/131152100

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值