问题来源 : ACWing
https://www.acwing.com/blog/content/277/
双指针
最长连续不重复子串长度
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
const int N = 100010;
int f[N];
int main() {
int n;
cin >> n;
for(int i = 0; i < n; i++) scanf("%d",&f[i]);
int ans = 0;
int le = 0;
set<int> st;
for(int i = 0; i < n; i++) {
if(st.count(f[i])) {
while(le < i && f[le] != f[i])
st.erase(f[le++]);
le++;
} else {
st.insert(f[i]);
}
ans = max(ans,i - le + 1);
}
cout << ans << endl;
return 0;
}
数组元素的目标和
#include <iostream>
using namespace std;
const int N = 100010;
int f[N],s[N];
int n,m,x;
int main() {
cin >> n >> m >> x;
for(int i = 0; i < n; i++) scanf("%d",&f[i]);
for(int i = 0; i < m; i++) scanf("%d",&s[i]);
for(int i = 0, j = m - 1; i < n; i++) {
while(j >= 0 && f[i] + s[j] > x) j--;
if(j >= 0 && f[i] + s[j] == x) { cout << i << " " << j << endl;break;}
}
// 二分
// int a,b;
// for(int i = 0; i < n; i++) {
// int num = x - f[i];
// int le = 0;
// int ri = m - 1;
// while(le < ri) {
// int mid = (le + ri) / 2;
// if(s[mid] < num) le = mid + 1;
// else if(s[mid] >= num) ri = mid;
// }
// if(num == s[le]) {
// cout << i << " "<<le << endl;
// break;
// }
// }
return 0;
}
二进制中1的个数
负数用补码表示的原因:
对于一个正数 X
,那么对于他的相反数-X
,一定有以下的关系X + (-X) = 0
。
那么 -x = 0 - x
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int f[N];
int n,m;
int slove() {
int cnt = 0;
while(m != 0) {
cnt ++;
m -= m & (-m); // -m == ~m + 1 lowbit(x)
}
return cnt;
}
int main() {
cin >> n;
for(int i = 0; i < n; i++) {
cin >> m;
f[i] = slove();
}
for(int i = 0; i < n; i++) printf("%d ",f[i]);
return 0;
}
区间和
因为题中的要求是在一个坐标轴中,每次对于某一个下标进行操作+c,-c
,并且坐标是存在负数的,范围还是-1e9 ~ 1e9
,但是实际用到的点最多3 * 1e5
个,就需要进行一次离散化。
- 读输入。将每次读入的
x c
push_back()到add
中,将每次读入的位置x
push_back()到all
中,将每次读入的l r
push_back()到query
中。 - 排序、离散化去重。
- 通过遍历
add
,完成在离散化的数组映射到的t数组
中进行加上c的操作,并进行差分 - 求前缀和。
- 通过遍历query,完成求区间
[l,r]
的和。
至于去重,就是为了让整个使用到的点的排列更紧促一点,让在二分查找
的时候不会出现对重复元素的查找,相对来说能快一点。C++中对于去重可以使用unique
函数,函数的返回值是所有不重复的区间的下一个位置的元素。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 3 * 1e5 + 10;
int n,m;
int x,c;
int l,r;
int f[N],t[N]; // 前缀和数组
typedef pair<int,int> PII;
vector<int> all; // 所有需要用到的点
vector<PII> add,query; // 需要操作的点,与需要求结果的区间
int find(int x) {
l = 0, r = all.size();
while(l < r) {
int mid = (l + r) >> 1;
if(all[mid] >= x) r = mid;
else if(all[mid] < x) l = mid + 1;
}
return l + 1; // 返回前缀和时数据的下标
}
vector<int>::iterator my_unique() {
int j = 1;
for(int i = 1; i < all.size(); i++) {
if(all[j - 1] != all[i]) all[j++] = all[i];
}
return all.begin() + j;
}
int main() {
cin >> n >> m;
for(int i = 0; i < n; i++) {
cin >> x >> c;
add.push_back(make_pair(x,c));
all.push_back(x);
}
for(int i = 0; i < m; i++) {
cin >> l >> r;
query.push_back(make_pair(l,r));
all.push_back(l);
all.push_back(r);
}
// 离散化 + 去重
sort(all.begin(),all.end());
all.erase(my_unique(),all.end());
//all.erase(unique(all.begin(),all.end()),all.end());
// 差分
for(auto item : add) {
int idx = find(item.first);
t[idx] += item.second;
}
// 前缀和
for(int i = 1; i <= all.size(); i++) f[i] = t[i] + f[i-1];
// 结果
for(auto item : query) {
int le = find(item.first), ri = find(item.second);
cout << f[ri] - f[le - 1] << endl;
}
return 0;
}
合并区间
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
typedef pair<int,int> PII;
vector<PII> add;
int n,ans;
void merage() {
sort(add.begin(),add.end());
int pre = add[0].second;
for(int i = 1; i < n; i++) {
if(add[i].first > pre) {
pre = add[i].second;
ans++;
} else {
pre = max(add[i].second,pre);
}
}
ans ++;
}
int main() {
cin >> n;
for(int i = 0; i < n; i++) {
int x,y;
cin >> x >> y;
add.push_back(make_pair(x,y));
}
merage();
cout << ans;
return 0;
}