题目
思路
- 二分查找的核心不是单调性、有序性,而是分段性。这是理解整个二分查找思想的核心。
- 二分查找分成两种情况,一种称为“左边多型”,即
[left, mid]
和[mid + 1, right]
,一种是“右边多”型”,即[left, mid - 1]
和[mid, right]
- 二者的模板分别如下:所谓
check[mid]
说明mid位置符合该区间需要的条件最后一个位置
左边多型:如果mid不符合左边的条件,那么 right = mid 最后的返回值代表蓝色的第一个位置
右边多型:如果mid不符合
using namespace std;
int main() { int nums[10] = {-1, -1, -1, -1, 1, 1, 1, 1, 1, 1}; // 左边多型:返回右边的最左位置 / int left = 0, right = 10 - 1; while (left < right) { int mid = left + (right - left) / 2; // 如果mid位置符合右边的条件 if (nums[mid] > 0) { right = mid; } else { // 动left, 说明取最左边的位置 left = mid + 1; } } // 返回最左位置 cout << left << “ “ << right << endl; /
int left = 0, right = 10 - 1;
while (left < right) {
int mid = (left + right + 1) >> 1;
// 如果mid位置符合左边的条件
if (nums[mid] < 0) {
left = mid;
} else {
// 动right,说明取最右边的位置
right = mid - 1;
}
}
// 返回最右位置
cout << right << endl;
return 0;
}
- 对于这道题而言,左右区间分别指的是:

- 左端点:
```cpp
int mid = (right + left) / 2
if (nums[mid] >= k) {
right = mid;
} else {
left = mid + 1;
}
- 右端点:
int mid = (left + right + 1) / 2 if (nums[mid] <= k) { left = mid; } else { right = mid - 1; }
代码
```cppinclude
include
using namespace std;
const int N = 1e6 + 10;
void query(int* nums, int target, int n) { int left = 0, right = n - 1; while (left < right) { int mid = (left + right) / 2; if (nums[mid] >= target) { right = mid; } else { left = mid + 1; } }
if (nums[left] == target)
cout << left << " ";
else
cout << "-1" << " ";
left = 0, right = n - 1;
while (left < right) {
int mid = (left + right + 1) >> 1;
if (nums[mid] <= target) {
left = mid;
} else {
right = mid - 1;
}
}
if (nums[right] == target)
cout << right << endl;
else
cout << "-1" << endl;
} int main() { int nums[N]; int n = 0, m = 0; cin >> n >> m; for (int i = 0; i < n; ++i) { cin >> nums[i]; }
for (int i = 0; i < m; ++i) {
int target = 0;
cin >> target;
query(nums, target, n);
}
return 0;
} ```