数组 - 704. 二分查找 - 代码随想录

41 阅读1分钟

题目链接:704. 二分查找

题目

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

相关题目推荐:

  • 35.搜索插入位置
  • 34.在排序数组中查找元素的第一个和最后一个位置
  • 69.x 的平方根
  • 367.有效的完全平方数

二分搜索的前提:数组为有序数组,且数组中无重复元素

Java代码

方法一:左闭右闭

class Solution(){ 
    public int search(int[] nums, target){ 
        int left = 0, right = nums.length - 1; 
        // 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
        if (target < nums[0] || target > nums[nums.length-1]) 
            return -1; 
        while (left <= right){ 
            int mid = left + ((right-left) >> 1); 
            if (nums[mid] == target) 
                return mid; 
            else if (nums[mid] > target) 
                right = mid - 1; 
            else if (nums[mid] < target) 
                left = mid + 1; 
        } 
            return -1; 
    } 
}
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

方法二:左闭右开

class Solution(){ 
    public int search(int[] nums, target){ 
        int left = 0, right = nums.length; 
        if (target < nums[0] || target > nums[nums.length-1]) 
            return -1; 
        while (left < right){ 
            int mid = left + ((right-left) >> 1); 
            if (nums[mid] == target) 
                return mid; 
            else if (nums[mid] > target) 
                right = mid; 
            else if (nums[mid] < target) 
                left = mid + 1; 
        } 
            return -1; 
    } 
}
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

二分查找易错点

1. 左右边界更新

left和right更新根据两种方法左闭右闭[left, right]和左闭右开[left, right)

i)左闭右闭[left, right]

int left = 0, right = nums.length - 1; 
...
while (left <= right){
    ...
    right = mid - 1;
    ...
    left = mid + 1;
}

i)左闭右开[left, right)

int left = 0, right = nums.length; 
...
while (left < right){
    ...
    right = mid;
    ...
    left = mid + 1;
}

2. 中间值定义

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

比较>>1位运算和/2除二取整

n为非负数时,>>1/2结果一样
n为负偶数时,>>1/2结果一样
n为负奇数时,>>1/2结果不一样
所以,奇数直接除2会发生截断现象,在n为负奇数时,>>1/2截断方向相反

避免溢出

若定义int mid = (left + right) / 2,期中left + right很可能导致溢出

综上,mid = left + ((right-left) >> 1)为最优解