​int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2​

​第一个,最基本的二分查找算法:​

因为我们初始化 right = nums.length - 1

所以决定了我们的「搜索区间」是 [left, right]

所以决定了 while (left <= right)

同时也决定了 left = mid+1 和 right = mid-1

因为我们只需找到一个 target 的索引即可

所以当 nums[mid] == target 时可以立即返回

​第二个,寻找左侧边界的二分查找:​

因为我们初始化 right = nums.length

所以决定了我们的「搜索区间」是 [left, right)

所以决定了 while (left < right)

同时也决定了 left = mid+1 和 right = mid

因为我们需找到 target 的最左侧索引

所以当 nums[mid] == target 时不要立即返回

而要收紧右侧边界以锁定左侧边界

​第三个,寻找右侧边界的二分查找:​

因为我们初始化 right = nums.length

所以决定了我们的「搜索区间」是 [left, right)

所以决定了 while (left < right)

同时也决定了 left = mid+1 和 right = mid

因为我们需找到 target 的最右侧索引

所以当 nums[mid] == target 时不要立即返回

而要收紧左侧边界以锁定右侧边界

又因为收紧左侧边界时必须 left = mid + 1

所以最后无论返回 left 还是 right,必须减一

class Solution {
public int[] searchRange(int[] nums, int target) {
int res[] = {-1,-1};

int l = 0, r = nums.length;

res[0] = findLeftBound(l, r, nums, target);
res[1] = findRightBound(l, r, nums, target);
return res;
}

private int findRightBound(int l, int r, int[] nums, int target) {
int mid = (l + r) / 2;
while (l < r) {
mid = (l + r) / 2;
if (nums[mid] <= target)
l = mid + 1;
else
r = mid;

}
if (l == 0) return -1;
return nums[l - 1] == target ? l-1 : -1;
}

private int findLeftBound(int l, int r, int[] nums, int target) {
int mid = (l + r) / 2;
while (l < r) {
mid = (l + r) / 2;
if (nums[mid] >= target)
r = mid;
else
l = mid + 1;

}
// target 比所有数都大
if (l == nums.length) return -1;
// 类似之前算法的处理方式
return nums[l ] == target ? l : -1;
}
}

参考资料

​边界问题​

​左右边界及边界详解​

​大于等于​