力扣数组

704.二分查找

704.二分查找

https://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. 定义查找区间 [left, right](初始为整个数组);
  2. 计算区间中间位置 midx,比较 nums[midx] 与目标值 target
  3. 根据比较结果缩小区间:
    • nums[midx] == target:找到目标,返回 mid
    • nums[midx] > target:目标在左半区间,调整右边界 right = midx - 1
    • nums[midx] < target:目标在右半区间,调整左边界 left = midx + 1
  4. 重复步骤 2-3,直到区间无效(left > right),说明目标不存在,返回 - 1。

解法

nums = [-1, 0, 3, 5, 9, 12]
target = 9

def binary_search(nums, target):
    left, right = 0, len(nums) - 1
    while left <= right:
        midx = left + (right - left) // 2
        if nums[midx] < target:
            left = midx + 1
        elif nums[midx] > target:
            right = midx - 1
        else:
            return midx
    return -1

解释

代码片段作用与原因
right = len(nums)-1闭区间 [0, len-1] 覆盖整个数组,符合 “左闭右闭” 的定义
while left <= rightleft == right 时,区间还有最后一个元素需要检查(如数组只有 1 个元素)
mid = left + (right-left)//2等价于(left+right)/2, 但避免 left+right 整数溢出,且 // 是向下取整(保证 mid 是整数下标)
right = midx - 1因为 nums[midx] > target,midx 本身已排除,右边界需左移一位
left = midx + 1因为 nums[midx] < target,midx 本身已排除,左边界需右移一位

进阶

如果数组有重复元素,基础版只能找到任意一个匹配项,如何找「第一个出现的位置」或「最后一个出现的位置」?