一、博客园
二、模板
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
三、Acwing 799
/*
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
双指针算法核心:优化
两根指针本来暴力求解是n^2级别,双指针运用某些单调性质优化后,时间复杂度变为n,
因为总体看来两根指针都是遍历序列一次
*/
#include<iostream>
using namespace std;
const int N=100010;
int n;
int a[N],b[N];
//a[N]存储整数序列,b[N]动态存储当前探索区间每个元素出现的次数
//注意a的数组范围是元素有多少个,b的数组范围是数组a中元素的取值范围
int main(){
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
int res=0;
for(int i=0,j=0;i<n;i++){//所求子序列可能以任意元素结尾,遍历每个元素
b[a[i]]++;//元素一个一个去加,如果有重复,一定是新加的元素重复
while(j<i&&b[a[i]]>1) b[a[j++]]--;
res=max(res,i-j+1);
}
cout<<res<<endl;
return 0;
}
AcWing 800. 数组元素的目标和
#include<iostream>
using namespace std;
const int N=100010;
int n,m,x;
int A[N],B[N];
int main(){
cin>>n>>m>>x;
for(int i=0;i<n;i++) cin>>A[i];
for(int i=0;i<m;i++) cin>>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) cout<<i<<' '<<j<<endl;
}
return 0;
}
AcWing 2816. 判断子序列
/*
序列a中每个元素能否顺次映射到b
从前往后扫描数组b,每次扫描时,查看数组b中当前数与数组a中当前数是否一样
如果一样,此时a[i]与b[j]匹配,i++
总之就是在数组b中一个一个找与a[i]相匹配的元素,匹配成功就i++
*/
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
int main()
{
cin>>n>>m;
for (int i = 0; i < n; i ++ ) cin>>a[i];
for (int i = 0; i < m; i ++ ) cin>>b[i];
int i = 0, j = 0;
while (i < n && j < m)
{
if (a[i] == b[j]) i ++ ;
j ++ ;
}
if (i == n) puts("Yes");
else puts("No");
return 0;
}
四、位运算
n>>k&1 求n的第k位数字
lowbit(n)=n&-n 的作用是求最后的1.
思路:
AcWing 801. 二进制中1的个数
输入第一个数代表:接下来输入的个数
输入的数转换二进制后,求出1的个数
/*
数字n的二进制表示中倒数第k位数是多少(k从0开始)
n>>k&1
先把第k位移到最后一位n>>k
再看个位是多少:&1
返回x最后一个1
lowbit(x)=x&-x
补码-x是对x取反+1
反码是对x取反
x=10100 lowbit(x)=100 树状数组的基本操作
*/
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
int res=0;
while(x){
x-=x&(-x);//每次把x中最后一个1减掉
res++;
}
cout<<res<<' ';
}
return 0;
}