双指针
//【双指针】
//题目:得到一个数组中的长度最长且其中元素不重复的子数组
//解法一:暴力枚举 -> 枚举出所有符合要求的子数组 O(n^2)
// 1.如何枚举所有的子数组呢? 两层for循坏 O(n^2)
// 2.如何判断枚举的子数组中, 所有的元素全都不相同? 借助哈希表 O(1)
//解法二:利用单调性,使用“同向双指针”来优化
// 性质:在暴力枚举的过程中,left 以及 right 其实是可以不回退的
// 怎么用? 用什么结构维护窗口的信息?
// 初始化:left = 1, right = 1, unorderet_map <int, int> mp;
// 进窗口:让right 所指的元素进入窗口 mp[a[right]]++;
// 判断:判断窗口是否合法 mp[a[right]] > 1;
// 出窗口:让left 所指的元素出窗口 mp[a[left]]--; (判断和出窗口循环)
// 更新结果: ret = max(ret, right - left + 1)
// 将原本需要两层循环的 O(n^2) 时间复杂度优化为 O(n)
include // 输入输出流
include <unordered_map> // 哈希表,用于快速统计元素出现次数
using namespace std;
typedef long long LL; // 定义长整型别名,这里数组元素用LL但实际逻辑不影响
const int N = 1e6 + 10; // 数组最大长度,1e6+10防止越界
LL a[N]; // 存储输入的数组
int main(){
int T; cin >> T; // 多组测试用例数量
int n;
while(T--){ // 处理每组测试用例
cin >> n; // 当前数组长度
for(int i = 1; i <= n; i++){
cin >> a[i]; // 输入数组元素(下标从1开始)
}
// 核心:滑动窗口找最长无重复子数组
int left = 1, right = 1; // 窗口左右边界,初始都在第一个元素
int ret = 0; // 记录最长长度,初始为0
unordered_map<int, int> mp; // 哈希表:key=数组元素,value=该元素在窗口内的出现次数
while(right <= n){ // 右边界没到数组末尾就继续
mp[a[right]]++; // 把右边界元素加入哈希表,计数+1
// 关键:如果当前右边界元素重复(计数>1),收缩左边界直到无重复
while(mp[a[right]] > 1){
mp[a[left]]--; // 左边界元素移出哈希表,计数-1
left++; // 左边界右移
}
// 更新最长无重复子数组长度(窗口长度=右-左+1)
ret = max(ret, right - left + 1);
right++; // 右边界右移,扩大窗口
}
cout << ret << endl; // 输出当前测试用例的结果
}
return 0;
}

浙公网安备 33010602011771号