二分查找只有一个思想,那就是:逐步缩小搜索区间
二分查找重点
for left < right
退出循环的时候有 left == right
成立,双指针重合分析二分查找的技巧是:不要出现 else,而是把所有情况用 else if 写清楚,清楚地展现所有细节
int binarySearch(int[] nums, int target) {
int left = 0, right = ...;
while(...) {
int mid = left + (right - left) /2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...
} else if (nums[mid] > target) {
right = ...
}
}
return ...;
}
func binarySearch(nums []int, target int) int {
left := 0
right := len(nums) - 1 // 注意细节
for left <= right {
mid := left + (right - left) / 2
if nums[mid] == target { // 找到目标值终止搜索
return mid
} else if nums[mid] < target {
left = mid + 1 // 下个搜索区间 [mid+1, right]
} else if nums[mid] > target {
right = mid - 1 // 下个搜索区间 [left, mid-1]
}
}
return -1
}
统计 target 数字出现次数,即用二分法查找左右边界
i = 0
右边界 j = len(nums) - 1
[i, j]
无元素时跳出
mid
nums[mid] < target
则 target 在 [mid+1, j]
执行 i = m + 1
nums[mid] > target
则 target 在 [i, mid-1]
执行 j = m - 1
nums[mid] == target
则 右边界 在 [mid+1, j]
左边界在 [i, mid-1]
分两种情况
i = mid + 1
跳出时 i
指向右边界j = mid - 1
跳出时 j
指向左边界func binarySearch(nums []int, target int, lower bool) int {
left, right, ans := 0, len(nums)-1, len(nums)
for left <= right {
mid := (left+right) / 2
if nums[mid] > target || // 找第一个大于 target 右边界
(lower && nums[mid] >= target) { // 找第一个等于 target 左边界
right = mid-1
ans = mid
} else {
left = mid+1
}
}
return ans
}
func search(nums []int, target int) (ans int) {
leftIdx := binarySearch(nums, target, true)
rightIdx := binarySearch(nums, target, false) - 1
if leftIdx <= rightIdx &&
rightIdx < len(nums) &&
nums[leftIdx] == target &&
nums[rightIdx] == target {
ans = rightIdx - leftIdx + 1
}
return
}