LeetCode704:二分查找


LeetCode地址

二分法要素

一个题解能不能使用二分法需要满足两个提前条件

  • 数组必须为有序
  • 数组中无重复元素: 一旦有重复元素,使用二分法返回的元素下表可能不唯一

第一种写法

解析

传进来目标值target是在一个左闭右闭的区间里,也就是在 [L , R] ,区间定义之后就决定了二分法的代码应该如何写了,

  • while(l <= r)要使用 <= 因为 l == r 是有意义的,所以使用<=
  • 当if(nums[mid] > target) r将要赋值为mid-1,因为当前这个num[mid]是大于target的,首先mid位置的数肯定不是target,大于那肯定就是在左边,因为数组是有序的,那接下来肯定是要在l 到 mid-1的位置进行二分查找,所以r要等于mid-1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Solution {
    // 第一个版本
    public int search(int[] nums, int target) {
    int l = 0;
    int r = nums.length -1 ;
    while(l <= r){
    // 求中间位置mid
    int mid = l + ((r -l) / 2); // 防止溢出
    if(nums[mid] > target){
    r = mid -1 ; // target大于mid得位置,说明mid右边得数都比target大,因此要在l - mid得范围找
    }else if (nums[mid] < target){
    l = mid+1; // 与上同理
    }else{
    return mid; // 找到了
    }
    }
    // 未找到目标值
    return -1;
    }
    }
    好家伙击败百分之百
    好家伙击败百分之百

第二种写法

左闭右开

l = 0 , r = nums.length 而不是 nums.length - 1,这种情况下, 当num[mid] > target 时候, r 是 直接赋值给mid,而不是r -1 , 因为是[l , r)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
// 第二个版本 左闭右开 [l , r )
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length; // 定义target在左闭右开的区间里,即:[left, right)
while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
int middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle; // target 在左区间,在[left, middle)中
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,在[middle + 1, right)中
} else { // nums[middle] == target
return middle; // 数组中找到目标值,直接返回下标
}
}
// 未找到目标值
return -1;
}
}