二分搜索
需要考虑:边界、加一与否等等
mid计算习惯要用:
left + (right - left) / 2
,避免直接相加导致溢出的情况。
寻找一个元素
即搜索一个数,如果存在,返回其索引,否则返回 -1。
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // 注意
while(left <= right) {
int mid = left + (right - left) / 2;
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1; // 注意
else if (nums[mid] > target)
right = mid - 1; // 注意
}
return -1;
}
-
终止条件:
left = right + 1
,此时区间为空 -
若使用:
while(left < right)
//... while(left < right) { // ... } return nums[left] == target ? left : -1;
寻找左侧边界
上面的算法不足以处理这种问题:比如说给你有序数组
nums = [1,2,2,2,3]
,target
为 2,此算法返回的索引是 2,没错。但是如果我想得到target
的左侧边界,即索引 1,或者我想得到target
的右侧边界,即索引 3,这样的话此算法是无法处理的。
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
// 搜索区间为 [left, right]
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
// 搜索区间变为 [mid+1, right]
left = mid + 1;
} else if (nums[mid] > target) {
// 搜索区间变为 [left, mid-1]
right = mid - 1;
} else if (nums[mid] == target) {
// 收缩右侧边界
right = mid - 1;
}
}
// 判断 target 是否存在于 nums 中
// 此时 target 比所有数都大,返回 -1
if (left == nums.length) return -1;
// 判断一下 nums[left] 是不是 target
return nums[left] == target ? left : -1;
}
寻找右侧边界
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 这里改成收缩左侧边界即可
left = mid + 1;
}
}
// 最后改成返回 left - 1
if (left - 1 < 0) return -1;
return nums[left - 1] == target ? (left - 1) : -1;
}
需要做到理解背诵默写!!!
今日推歌
------《活该》
谁不曾有过贼荒唐的青春
谁又信誓旦旦说爱你永远不变
当我唱起那熟悉的老歌
是否你也想起那年的夏天