双指针算法的一个简单题解

题目是这样的:
给定一个长度为 n
的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
输入格式
第一行包含整数 n

第二行包含 n
个整数(均在 0∼105
范围内),表示整数序列。
输出格式
共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。
数据范围
1≤n≤105
输入样例:
5
1 2 2 3 5
输出样例:
3
这题用双指针算法,先介绍一下双指针算法,双指针算法最大的一个好处便是把时间复杂度从o(n**2)降低到o(n),这道题如果我们使用朴素的暴力枚举是可以做的,最好的枚举结果是
int res = 0

for(int i = 1;i <= n; i ++)

for(int j = 1;j <= i;j ++)
{
if check(i,j)//这里的函数是判断i到j之间有无重复元素

  continue;

else

  res = max(res,i - j + 1);

}

这段代码的时间复杂度是O(n^2)。

解析:

外层循环从1到n,共执行n次。
内层循环在最坏情况下(即每次i都满足check(i, j)条件)会执行i次,因此总的执行次数为1 + 2 + ... + n = n * (n + 1) / 2,这是一个关于n的二次函数。
因此,时间复杂度为O(n^2)。
为什么双指针算法的时间复杂度是o(n)呢?
第一层循环枚举n次,但第二层的执行次数最多是n次,属于o(1)的复杂度,所以总的时间复杂度便是o(n)的复杂度。

附上本题的c++代码:

include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n;
int a[N],s[N];//a是原数组,s是统计从j到i之间每个元素出现的次数

int main()
{
int res = 0;//答案
cin >> n;
for(int i = 0;i < n;i ++) cin >> a[i];

for(int i = 0,j = 0;i < n;i ++)
{
	s[a[i]] ++;
	
	while(s[a[i]] > 1)
	{
		s[a[j]] --;//移动j指针,直到没有重复的元素
		j ++;
	}//这部分代码当这次枚举的i与上一次的重复时会执行
	
	res = max(res , i - j + 1);
}

cout << res << endl;

return 0;

}
若有不足之处还望指出,感谢您的浏览!