目录
1、双指针算法
1.1、指向两个序列的双指针
归并排序利用了双指针算法
一个指针指向一个序列,另外一个指针指向另一个序列。
1.2、指向一个序列的双指针
例如:快速排序
1.3 双指针算法的通用模板
1.4 双指针算法的核心思想
1.5 例子:输出句子中的单词
1.6 最长连续不重复子序列
如何思考双指针。
先枚举终点,再枚举起点。
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N],s[N];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int res=0;
for(int i=0,j=0;i<n;i++)
{
//将出现的数字+1
s[a[i]]++;
while(s[a[i]]>1)
{
//数字<=1不重复,>1表示重复。则重复之前的全部--
//原来为1的变为0,为2的变为1。为2的只有一个
//就是此时的s[a[i]]。将计数为2变成1,--结束。
//while一轮后,i到了与a[i],相同数字的下一个坐标。
s[a[j++]]--;
}
res=max(res,i-j+1);
}
cout<<res;
return 0;
}
1.7 双指针思路总结
先写一个暴力o(n^2)的做法,找i与j的单调关系。通过单调性使用双指针将时间复杂度降到o(n).
1.8 数组元素的目标和
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int main()
{
int n,m,x;
scanf("%d%d%d",&n,&m,&x);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=0;i<m;i++) scanf("%d",&b[i]);
for(int i=0,j=m-1;i<n;i++)
{
while(j>=0&&a[i]+b[j]>x) j--;
if(j>=0&&a[i]+b[j]==x) printf("%d %d",i,j);
}
return 0;
}
1.9 判断子序列
2、位运算
2.1 二进制中1的个数
2.2 lowbit 树状数组的基本操作
2.3作用:二进制中1的个数
2.5 原码 反码 补码
3、人类做题思路 dfs
到最后 ,就是每一个节点。节点掌握了,题目就解决了。
4、整数 且有序 离散化
4.1区间和
4.1.1 数据大小分析
4.1.2 解题思路
将原先离散的坐标,映射成相邻的坐标。本题映射之后,下标由2千万变成30万
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;
int n, m;
int a[N], s[N];
vector<int> alls;
vector<PII> add, query;
int find(int x)
{
int l = 0, r = alls.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (alls[mid] >= x) r = mid;
else l = mid + 1;
}
return r + 1;
}
vector<int>::iterator unique(vector<int> &a)
{
int j = 0;
for (int i = 0; i < a.size(); i ++ )
if (!i || a[i] != a[i - 1])
a[j ++ ] = a[i];
// a[0] ~ a[j - 1] 所有a中不重复的数
return a.begin() + j;
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i ++ )
{
int x, c;
cin >> x >> c;
add.push_back({x, c});
alls.push_back(x);
}
for (int i = 0; i < m; i ++ )
{
int l, r;
cin >> l >> r;
query.push_back({l, r});
alls.push_back(l);
alls.push_back(r);
}
// 去重
sort(alls.begin(), alls.end());
alls.erase(unique(alls), alls.end());
// 处理插入
for (auto item : add)
{
int x = find(item.first);
a[x] += item.second;
}
// 预处理前缀和
for (int i = 1; i <= alls.size(); i ++ ) s[i] = s[i - 1] + a[i];
// 处理询问
for (auto item : query)
{
int l = find(item.first), r = find(item.second);
cout << s[r] - s[l - 1] << endl;
}
return 0;
}
4.1.3 unique 编写思路
5、区间合并
4.1 介绍区间合并
4.2 算法分析
4.3 代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
void merge(vector<PII> &segs)
{
vector<PII> res;
sort(segs.begin(), segs.end());
int st = -2e9, ed = -2e9;
for (auto seg : segs)
if (ed < seg.first)
{
if (st != -2e9) res.push_back({st, ed});
st = seg.first, ed = seg.second;
}
else ed = max(ed, seg.second);
if (st != -2e9) res.push_back({st, ed});
segs = res;
}
int main()
{
int n;
scanf("%d", &n);
vector<PII> segs;
for (int i = 0; i < n; i ++ )
{
int l, r;
scanf("%d%d", &l, &r);
segs.push_back({l, r});
}
merge(segs);
cout << segs.size() << endl;
return 0;
}