紫书刷题进行中,题解系列【GitHub|CSDN】
例题8-7 UVA11572 Unique Snowflakes(25行AC代码)
题目大意
给定一个序列,求一个连续,无重复元素的最长序列。
思路分析
如果直接枚举任意长度的连续序列,复杂度为O(n2),再加上set判重O(logn),总时间复杂度为O(n2logn),显然需要优化。这里可以用双指针/滑动窗口优化
设置指向当前区间的左右指针pl,pr,均初始化为0;用set判重,存储当前区间的元素;令ans记录最长区间,初值为0。
- 若A[pr]在set中不存在,则直接插入set,并判断是否更新最长区间长度ans
- 若A[pr]在set中,则从pl开始,将A[pl]从set删除,直至遇到A[pl]=A[pr],更新ans
以上算法时间复杂度为O(nlogn)
注意点
- 若为了优化查询时间,可手写哈希函数,或者用stl的
unordered_set
,复杂度接近O(n)
AC代码(C++11,双指针/滑动窗口)
#include<bits/stdc++.h>
using namespace std;
int T, n;
int main() {
scanf("%d", &T);
while (T --) {
scanf("%d", &n);
int ans=0, a, pl=0, pr=0;
unordered_set<int> _set; vector<int> vec; // 查询接近哈希时间
// set<int> _set; vector<int> vec;
for (int i=0; i < n; i ++) { scanf("%d", &a); vec.push_back(a);} // 输入
while (pr < n) { // 枚举数组元素
if (_set.find(vec[pr]) == _set.end()) { // 不存在
_set.insert(vec[pr]);
ans = max(ans, pr-pl+1); // 取大者
}
else { // 存在
for ( ; pl < pr && vec[pl] != vec[pr]; pl ++) _set.erase(vec[pl]); // 删除
pl ++; // 最后一个vec[pl]没有删除,这里需手动移动下标
}
pr ++; // 下一个元素
}
printf("%d\n", ans);
}
return 0;
}