acwing799.https://www.acwing.com/problem/content/801/
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], s[N], n, res;//a[N]是序列,s[N]记录每一个数出现的次数
int main()
{
cin >> n;
for(int i = 0; i < n; i ++)//输入
cin >> a[i];
for (int j = 0, i = 0; i < n; i ++)//i,j两个指针,i一定在j前面
{
s[a[i]] ++;//i指针走在哪,那个数+1
while(s[a[i]] == 2)//如果重复执行循环
{
s[a[j]] --;//减去这个数的个数
j ++;//前进一步
}
res = max (res, i - j + 1);
}
cout<<res;
return 0;
}
核心思路
- 遍历数组a中的每一个元素a[i], 对于每一个i,找到j使得双指针[j, i]维护的是以a[i]结尾的最长连续不重复子序列,长度为i - j + 1, 将这一长度与r的较大者更新给r。
- 对于每一个i,如何确定j的位置:由于[j,i-1]是前一步得到的最长连续不重复子序列,所以如果[j, i]中有重复元素,一定是a[i],因此右移j直到a[i]不重复为止(由于[j, i - 1]已经是前一步的最优解,此时j只可能右移以剔除重复元素a[i],不可能左移增加元素,因此,j具有“单调性”、本题可用双指针降低复杂度)。
- 用数组s记录子序列a[j-i]中各元素出现次数,遍历过程中对于每一个i有三步操作:将a[i]出现次数s[a[i]]加1 -> 若a[i]重复则右移j(s[a[j]]要减1) -> 确定j及更新当前长度i - j + 1给r。
acwing800 https://www.acwing.com/problem/content/description/802/
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int a[N], b[N], n, m, x;
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(a[i] + b[j] > x) j --;//大了j就退,直到a+b最小的j,这一步必须放在第一步
if(a[i] + b[j] == x)
{
cout<<i<<' '<<j;
return 0;
}
}
return 0;
}
双指针的核心:将上一状态指针所表达的信息传递至下一状态,从而减少无谓的搜索。