双指针算法
其实我们之前就接触过双指针算法,在归并排序中,两个有序序列合并成一个更大的有序序列时,就有两个指针分别指向这两个有序序列
不过两个指针分别指向两个序列只是双指针算法的其中第一大类
第二大类就是两个指针同时指向一个序列,例如在快排中,一开始就有一个指针指向了区间的开头,一个指针指向了区间的末尾
双指针算法的模版
for(int i = 0, j = 0; i < n ; i++)
{
while(i < j && check ()) //check()函数代表是否满足某种情况
{
j++;
}
//每道题目的具体实现
}
核心思想:将朴素(暴力)算法时间复杂度O()优化到O(n)
for(int i = 0; i < n ;i ++ )
{
for(int j = 0 ; j < n ; j ++)
{
}
}
题目
输入
5 1 2 2 3 5
输出
3
代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N], s[N];
int main(void)
{
int n;
int res = 0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
for (int j = 0, i = 0; i < n; i++)
{
s[a[i]]++;
while (s[a[i]] > 1)
{
s[a[j]]--;
j++;
}
res = max(res, i - j + 1);
}
printf("%dn", res);
return 0;
}
代码用到了哈希表,s数组存储着a[i]出现的次数,j指向最长子序列的最左端,i指向最右端,例如题目中的输入1 2 2 3 5,
i等于0时,会将s[1]++;
i等于1时,会将s[2]++;
i等于2时,会将s[2]++; 这时while循环中的条件成立,因为s[2]等于2 > 1(在上个循环中已经更新了max的大小为2)
所以j会将s[a[j]--],然后j++,循环到j==i会把s[1]变为0,s[2]变为1(也就是将刚刚所有为1的s[]变成0,大于1的变成1)这时i==j,然后i再开始移动,目前s数组里只有s[2]等于1
i等于3时,会将s[3]++;
i等于4时,会将s[5]++;
i=2,j=4,所以max会被更新为3