一、用途

在数组中查找某一特定值的函数并获取其下标。

二、限制条件

1.有序数组

所查找的数组中的所有元素必须按照从小到大或从大到小的顺序排列。
如果所查找的数组不是有序数组,也可使用sort()库函数将其转化为升序排列的有序数组后再进行查找。其中sort()函数位于C++的algorithm库中,其具体用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> arr = {1, 3, 5, 6, 9, 12};

// 默认为升序排序
sort(arr, arr + n);
// 降序排列
sort(arr, arr + n, greater<int>());

2.数组中无重复元素

若存在重复元素,函数将返回其中某一个元素的地址。

三、时空复杂度

  • 时间复杂度:O(logn)O(logn)
  • 空间复杂度:O(1)O(1)

四、查找区间的两种模式

1. target定义在左闭右闭区间

例题:搜索插入位置(LeetCode)
题目描述:

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2
输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 为 无重复元素升序 排列数组
-104 <= target <= 104

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

int main() {
int target;
cin >> target;
cin.ignore(); // 清理换行符
string line;
getline(cin, line);

vector<int> nums;
int num;
istringstream stream(line);
while (stream >> num) {
nums.push_back(num);
}

int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
cout << mid << endl;
return 0;
}
}
// 如果没有找到目标值,则返回插入位置
cout << left << endl;
return 0;
}

2.target定义在左闭右开区间

例题:704.二分查找(LeetCode)
题目描述:

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
提示:
你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

int main() {
int target;
cin >> target;
cin.ignore(); // 清理换行符

string line;
getline(cin, line);

vector<int> nums;
int num;
istringstream stream(line);
while (stream >> num) {
nums.push_back(num);
}

int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
cout << mid << endl;
return 0;
}
}

cout << -1 << endl;
return 0;
}

五、注意事项

1
2
// int middle;
middle = left + ((right - left) >> 1); // 防止两数相加导致大数溢出