双指针
通用模板:
1 | for(int i=1,j=1;i<=n;i++){ |
核心思想:
将$O(n^2)$的朴素算法:
1 | for(int i=1;i<=n;i++){ |
通过某种性质(当$i$移动时,$j$只会向后移动或不动(单调性)),优化成$O(n)$
例:给定一个$n$项数列$s$,求最长连续不重复子序列(连续,不包含重复元素的最长子序列)的长度
分析:暴力做法:
1 | for(int i=1;i<=n;i++){ |
通过分析可以发现,当$i$增加时,$j$一定不会减小(当$i=a,j=b$时,若$j=b-1$,则序列中有重复元素,当$i=a+1$时,$j$若减小,必然包含$s[b-1]$,则序列中必有重复元素),因此可以使用双指针:
1 | for(int i=1,j=1;i<=n;i++){ |
再考虑$check$,不难想到,可以用数组$b$记录$[j,i]$中数组出现的个数,但这样依旧会超时,于是考虑优化。
可以发现,每次$i$增加$1$时,只有$b[s[i]]$会增加$1$,而之前已经保证$b$中每个元素都小于等于$1$,所以只用考虑$b[s[i]]$,则增加$j$之前$b[s[j]]–$,每次判断$b[s[i]]$是否为$1$,若为$1$,则$j$满足要求,记录答案。不难看出,当$b[s[i]]=1$是,$j$一定小于等于$i$,可以不用判断。
代码实现如下:
1 |
|