双指针算法

其实我们之前就接触过双指针算法,在归并排序中,两个有序序列合并成一个更大的有序序列时,就有两个指针分别指向这两个有序序列

不过两个指针分别指向两个序列只是双指针算法的其中第一大类

第二大类就是两个指针同时指向一个序列,例如在快排中,一开始就有一个指针指向了区间的开头,一个指针指向了区间的末尾

双指针算法的模版

for(int i = 0, j = 0; i < n ; i++)
{
    while(i < j && check ()) //check()函数代表是否满足某种情况
    {
        j++;
    }
    
    //每道题目的具体实现
}

核心思想:将朴素(暴力)算法时间复杂度O(n^{2})优化到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