logo头像
Snippet 博客主题

算法学习:二分查找

本文于 434 天之前发表,文中内容可能已经过时。

一、 原则

1. 区间:左右闭区间

2. while结束设定为<=

3. 左右界更新都为mid上下1

  1. 二分查找可以设定左闭右开的写法,也可以左右都是闭区间,这里设定后者

  2. 在1的设定下,如果left=right,即当前搜索区间长度为1,如果while里面不是<=二是严格<,那么该长度为1的区间就不会搜索,出现遗漏

  3. 在1,2的设定之下,必须让left、right的更新机制在循环结束后,right在left的左边,即每次更新right与left必须都不能为mid,因为mid可能 在区间长度为1或者2的时候mid等于其中的left,必须使得right与left有机制在更新时不能一直等于mid,故有原则3

二、三种情况

2.1 直接找元素

int searchBinary(int[] nums, int target) {
    //原则1 左右闭区间
    int left = 0, right = nums.length - 1;
    //原则2 while结束条件为<=
    while (left <= right) {
        int mid = left + ((right - left) >> 1);
        if (nums[mid] == target) {
            return mid;
        } else if (nums[mid] < target) {
            //原则3 左右界更新为mid加减1
            left = mid + 1;
        } else {
            //原则3 左右界更新为mid加减1
            right = mid - 1;
        }
    }
    return -1;
}

2.2 寻找左右边界

给定有序数组

如何找第一个2出现的下标或者最后一个2出现的下标

  • 找第一个:找左边界
int searchLeftBound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + ((right - left) >> 1);
        if (nums[mid] == target) {
            right = mid - 1; // 收缩右边界
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    // 越界检查,不存在检查
    if (left >= nums.length || nums[left] != target) {
        return -1;
    }
    return left;
}
  • 找最后一个:找右边界

int searchRightBound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + ((right - left) >> 1);
        if (nums[mid] == target) {
            left = mid + 1; // 收缩左边界
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    if (right < 0 || nums[right] != target) {
        return -1;
    }
    return right;
}