准确值,左边界,右边界。
- 精准值
int search(vector<int>& a, int t) {
int l = 0, r = a.size() - 1;
while (l <= r){
int mid = l + (r-l)/2;
if (a[mid] == t) return mid; //
else if (a[mid] < t) l = mid + 1;
else r = mid -1;
}
return -1;
}
- 从左边查左边界. >=target
int l = 0, r = a.size() ;
while (l < r){
int mid = l + (r-l)/2;
if (a[mid] < t) l = mid + 1;
else r = mid;
}
return l;
- 从右边查右边界. <=target
int l = 0, r = a.size() ;
while (l < r){
int mid = l + (r-l)/2;
if (a[mid] <= t) l = mid + 1; //因为有等于,所以l最后一下会越过去.l-1即为右界
else r = mid;
}
return l - 1;//注意些边界,精准查时特判a[mid]==t return mid;
例题:789. 数的范围
给定一个按照升序排列的长度为 n的整数数组,以及 q个查询。
对于每个查询,返回一个元素 k的起始位置和终止位置(位置从 0开始计数)。如果没有返回-1 -1
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
//binary search of k, left and right range 区间's index
PII solve(vector<int> a, int k){
int l = 0, r = a.size();
while (l < r){
int mid = l + (r - l) / 2;
if (a[mid] < k) l = mid + 1;
else r = mid;
}
int left = l;
int l2 = 0, r2 = a.size();
while (l2 < r2){
int mid = l2 + (r2 - l2)/2;
if (a[mid] <= k) l2 = mid + 1;
else r2 = mid;
}
int right = l2 - 1;
if (left >= a.size()||a[left]!=k) return {-1,-1};
return {left,right};
}
int main(){
int n, q;
cin >> n >> q;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < q; i ++ ){
int k;
cin >> k;
auto result = solve(a,k);
cout << result.first << " " << result.second << '\n';
}
return 0;
}
二维二分。
简单起见就不用双二分了,循环+每行二分。
bool Find(int target, vector<vector<int>>& a) {
if (a.empty() || a[0].empty()) return false;
int m = a.size(), n = a[0].size();
for (int i = 0; i < m;i++){
int l = 0, r = n;
while(l < r){
int mid = l + (r - l)/2;
if (a[i][mid] == target){ return true; break;}
if (a[i][mid] < target){ l = mid + 1;}
else{r = mid;}
}
}
return false;
}
旋转数组:
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
输入:
[3,4,5,1,2]
返回值:
1
int minNumberInRotateArray(vector<int>& nums) {
// write code here
int carry = -1;
for (int i = 0; i < nums.size();i++){
if (nums[i] < carry){
return nums[i];
break;
}
carry = nums[i];
}
return nums[0]; //太坑了 竟然给不旋转的混进来 [1,2,2,2,2,2]
}
山峰O(n)遍历
int findPeakElement(vector<int>& nums) {
// write code here
if (nums.size()<=1) return 0;
int carry = INT_MIN;
for (int i = 0; i < nums.size();i++){
if (nums[i] < carry){
return i-1;
break;
}
//cout << carry << ' ' << "i是" << i <<'\n';
carry = nums[i];
}
return nums.size()-1; //一路递增的山峰
}
二分O(log_2 n) (其中一个山峰即可)
int findPeakElement(vector<int>& a) {
if (a.size()<=1) return 0;
int l = 0, r = a.size()-1;
while (l < r){
int mid = l + (r - l)/2;
if (a[mid] < a[mid + 1]) l = mid + 1;
else r = mid;
}
return l;
}