1. 问题
【例题】循环输入,每组数据为给定 n 个元素的升序整型数组 nums 和一个值 target,要求实现一个函数查找 nums 中 target 的下标,如果查找不到则返回 -1.
2. 思路
3. 代码
int find(int n, int a[], int target)
{
int l = 0;
int r = n - 1;
while (l <= r)
{
int middle = (l + r) / 2;
if (a[middle] < target)
{
l = middle + 1;
}
else if (a[middle] > target)
{
r = middle - 1;
}
else
{
return middle;
}
}
return -1;
}
int main()
{
int n, target, ret;
std::cout << "input number of n " << std::endl;
while (std::cin >> n)
{
int b[n] = {0};
for (int i = 0; i < n; i++)
{
std::cin >> b[i];
}
std::cout << "input target " << std::endl;
std::cin >> target;
ret = find(n, b, target);
std::cout << "location:" << ret << std::endl;
}
return 0;
}
4. 二分法模板
二分搜索的一个技巧:不要出现 else
,而是把所有的情况用 else if
写清楚,因为这样可以清楚的展现所有的细节。
func binarySearch(a []int, target int) int {
left := 0
right := len(a) - 1
// 因为搜素区间是 [left, right],左右都是封闭的,所以循环时应该是 <=
for left <= right {
mid := left + (right-left)/2
if a[mid] == target {
return mid
} else if a[mid] < target {
left = mid + 1
} else if a[mid] > target {
right = mid - 1
}
}
return -1
}
5. 寻找左侧边界的二分法
package main
import (
"fmt"
)
func leftBinarySearch(a []int, target int) int {
left := 0
right := len(a) - 1
// 因为搜素区间是 [left, right],左右都是封闭的,所以循环时应该是 <=
for left <= right {
mid := left + (right-left)/2
if a[mid] == target {
// 不要返回,收缩右边界,逐步锁定左侧边界
right = mid - 1
} else if a[mid] < target {
left = mid + 1
} else if a[mid] > target {
right = mid - 1
}
}
// 上面循环结束时 left = right + 1 ,所以当 target 比 a 中所有元素都大时,
// 会存在 left 越界的情况
if left >= len(a) || a[left] != target {
return -1
}
return left
}
func main() {
arr := []int{1, 2, 3, 4, 4, 7, 7, 8, 9}
fmt.Println(leftBinarySearch(arr, 4))
}
6. 寻找右侧边界的二分法
package main
import (
"fmt"
)
func rightBinarySearch(a []int, target int) int {
left := 0
right := len(a) - 1
// 因为搜素区间是 [left, right],左右都是封闭的,所以循环时应该是 <=
for left <= right {
mid := left + (right-left)/2
if a[mid] == target {
// 不要返回,收缩左边界,逐步锁定右侧边界
left = mid + 1
} else if a[mid] < target {
left = mid + 1
} else if a[mid] > target {
right = mid - 1
}
}
// 上面循环结束时 left = right + 1 ,所以当 target 比 a 中所有元素都小时,
// right 会被减小到 -1,会存在 right 越界的情况
if right < 0 || a[right] != target {
return -1
}
return right
}
func main() {
arr := []int{1, 2, 3, 4, 4, 7, 7, 8, 9}
fmt.Println(rightBinarySearch(arr, 4))
}