bsearch_upper 中,mid = l + (r - l) / 2 + 1: 一个mid = (l + r) >> 1 一个mid = (l + r + 1) >> 1 加不加 1,完全取决于 l = mid 还是 r = mid l 等于 mid 时必须 +1 向上取整,不然会陷入 l = l 的死循环 r = mid 时候不用加 1,因为下一步 l = r 直接会退出循环
// 寻找大于等于 x 的下限 intbsearch_lower(int l, int r, int x){ while (l < r){ int mid = l + (r - l) / 2; if (q[mid] >= x) r = mid; // 降序改为 <= else l = mid + 1; } return l; }
// 寻找小于等于 x 的上限 intbsearch_upper(int l, int r, int x){ while (l < r){ int mid = l + (r - l) / 2 + 1; // 需要 + 1,防止死循环 if (q[mid] <= x) l = mid; // 降序改为 >= else r = mid - 1; } return l; }
intlower_bound(int l, int r, int x){ while (l < r) { int mid = l + (r - l) / 2; if (q[mid] <= x) r = mid; else l = mid + 1; } return l; } intupper_bound(int l, int r, int x){ while (l < r) { int mid = l + (r - l) / 2; if (q[mid] < x) r = mid; else l = mid + 1; } return l; }
为了方便记忆,可以理解为: 找第一个 >= x 的数,if 中就用 >= 找最后一个 <= x 的数,if 中就用 <=
// 最小化查找(可行区在右侧):查找第一个 >= x的数的下标 intbsearch_lower(int l, int r, int x){ while (l + 1 < r){ // l + 1 = r时结束 int mid = l + (r - l) / 2; if (q[mid] >= x) r = mid; else l = mid; } return r; }
// 最大化查找(可行区在左侧):查找最后一个 <= x的数的下标 intbsearch_upper(int l, int r, int x){ while (l + 1 < r){ // l + 1 = r 时结束 int mid = l + (r - l) / 2; if (q[mid] <= x) l = mid; else r = mid; } return l; }
4、STL 内置方法
lower_bound:
升序:
int p = lower_bound(q, q + n, x) - q;
降序:
int p = lower_bound(q, q + n, x, greater<int>()) - q;
upper_bound:
升序:
int p = upper_bound(q, q + n, x) - q;
降序:
int p = upper_bound(q, q + n, x, greater<int>()) - q;
这两个模板是一定有答案的,如果没有答案,那就只能是题目数据里没有,所以才会输出 -1 -1,对应就是代码里的 if 不成立的条件。
1、yxc
#include<bits/stdc++.h> #define int long long usingnamespace std;
constint N = 1e5 + 10; int n, m, q[N]; intbsearch_lower(int l, int r, int x); intbsearch_upper(int l, int r, int x);
signedmain(void) { scanf("%lld %lld", &n, &m); for (int i = 0; i < n; i ++ ) scanf("%lld", &q[i]); while (m--){ int x; scanf("%lld", &x); if (x != q[bsearch_lower(0, n - 1, x)]) cout << "-1 -1" << endl; else { cout << bsearch_lower(0, n - 1, x) << " "; cout << bsearch_upper(0, n - 1, x) << endl; } } return0; }
intbsearch_lower(int l, int r, int x){ while (l < r){ int mid = l + (r - l) / 2; if (q[mid] >= x) r = mid; else l = mid + 1; } return l; }
intbsearch_upper(int l, int r, int x){ while (l < r){ int mid = l + (r - l) / 2 + 1; if (q[mid] <= x) l = mid; else r = mid - 1; } return l; }
2、董晓算法
我喜欢这个。
#include<bits/stdc++.h> #define int long long usingnamespace std;
constint N = 1e5 + 10; int n, m, q[N]; intbsearch_lower(int l, int r, int k); intbsearch_upper(int l, int r, int k);
signedmain(void) { scanf("%lld %lld", &n, &m); for (int i = 0; i < n; i ++ ) scanf("%lld", &q[i]); while (m--){ int x; scanf("%lld", &x); if (q[bsearch_lower(-1, n, x)] != x) cout << "-1 -1" << endl; else { cout << bsearch_lower(-1, n, x)<< " "; cout << bsearch_upper(-1, n, x)<< endl; } } return0; }
// 最小化查找(可行区在右侧):查找第一个 >= x的数的下标 intbsearch_lower(int l, int r, int x){ while (l + 1 < r){ // l + 1 = r时结束 int mid = l + (r - l) / 2; if (x <= q[mid]) r = mid; else l = mid; } return r; }
// 最大化查找(可行区在左侧):查找最后一个 <= x的数的下标 intbsearch_upper(int l, int r, int x){ while (l + 1 < r){ // l + 1 = r 时结束 int mid = l + (r - l) / 2; if (x >= q[mid]) l = mid; else r = mid; } return l; }
3、糖豆爸爸
#include<bits/stdc++.h> usingnamespace std;
constint N = 100010; int n, q[N];
// 左闭右开 [ ) intlower_bound(int l, int r, int x){ while (l < r) { int mid = (l + r) >> 1; if (q[mid] >= x) r = mid; else l = mid + 1; } return l; } intupper_bound(int l, int r, int x){ while (l < r) { int mid = (l + r) >> 1; if (q[mid] > x) r = mid; else l = mid + 1; } return l; } intmain(){ int T; cin >> n >> T; for (int i = 0; i < n; i++) cin >> q[i]; while (T--) { int x; cin >> x; int p = lower_bound(0, n, x); //[0,n) if (q[p] != x) { puts("-1 -1"); continue; } printf("%d ", p); p = upper_bound(0, n, x); printf("%d\n", p - 1); } return0; }