// 二分查找 int left, right, mid, ans; left = 1; right = n; ans = -1; while (left <= right) { mid = left + (right-left) / 2; if (v[mid] > a) { right = mid - 1; } elseif (v[mid] < a) { left = mid + 1; } else { ans = mid; break; } } cout << ans << " ";
int v[1000010]; int n, m, a; intmain(){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", v+i); while (m--) { scanf("%d", &a); int left, right, mid, ans; left = 1; right = n; ans = -1; while (left <= right) { mid = left + (right-left)/2; if (v[mid] > a) { right = mid - 1; } elseif (v[mid] < a) { left = mid + 1; } else { // 如果找到,则比较 ans 的值,更新它 if (ans == -1 || ans > mid) ans = mid; right = mid - 1; } } cout << ans << " "; } cout << endl; return0; }
int v[1000010]; int n, m, a; intmain(){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", v+i); while (m--) { scanf("%d", &a); int l, r, mid; l = 1; r = n+1; while (l < r) { mid = l + (r-l)/2; if (a > v[mid]) l = mid + 1; else r = mid; } if (l < n+1 && v[l] == a) cout << l << " "; else cout << -1 << " "; } cout << endl; return0; }
另外,以上这种代码其实是不停在[l,mid) 和 [mid+1, r)之间做选择,所以:
l 只会更新成 mid+1
r 只会更新成 mid
如果记不清楚,就分开写:
如果猜对了但要找最小值,就更新 r
如果 mid 大了,则答案在 mid 左侧,就更新 r
如果 mid 小了,则答案在 mid 右侧,就更新 l
另外,以上这种代码其实是不停在[l,mid) 和 [mid+1, r)之间做选择,所以:
l 只会更新成 mid+1
r 只会更新成 mid
最后答案如果有,则在 l 位置,当然 l 位置也可能不是答案:
如果目标极小,没找到,则 l 位置为查找的范围最左侧下标
如果目标极大,没找到,则 l 位置为最初的 r 的位置(那个位置是最后一个元素的下一个位置,直接读取会数组越界)
lower_bound
其实上面那个写法就是 C++ STL 里面的 lowerbound 函数,所以我们可以直接用 lowerbound 函数来实现 P2249 题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include<bits/stdc++.h> usingnamespace std;
int v[1000010]; int n, m, a; intmain(){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", v+i); while (m--) { scanf("%d", &a); int l = lower_bound(v+1, v+n+1, a) - v; if (l < n+1 && v[l] == a) cout << l << " "; else cout << -1 << " "; } cout << endl; return0; }