问题:
输入一个长度为n的序列A,找到一个最长的连续子序列,使得该序列中没有重复的元素。
分析:
假设序列元素从0编号,所求子序列的左端索引为L,右端索引为R。首先,L和R从0开始。
①判断A[R]是否在子序列中,如果不在子序列中,R增大;如果在子序列中,R无法增大。
②求连续子序列最大长度。
③L向右增大一,重复①②,直到R超出序列A的范围。
set集保存A[L-R] 中的元素,R+1,把元素插入到set集中;L+1,从set集中删除元素。
代码如下:
#include <cstdio>
#include <set>
using namespace std;
const int maxn = 100;
int A[maxn];
int main(){
int n;
printf("序列长度n:");
scanf("%d",&n);
printf("序列:");
for(int i = 0; i < n; i++) scanf("%d",A+i);
set <int> s;
int L = 0, R = 0, ans = 0;
while(R < n){
// 增大R ,插入元素
while(R < n && !s.count(A[R])) s.insert(A[R++]);
// 求子序列的最大长度
ans = max(ans, R-L);
// 增大L ,删除元素
s.erase(A[L++]);
}
printf("连续子序列长度:%d",ans);
return 0;
}
map求出last[i],即A[i] 的上一个相同元素的下标。当上一个相同元素的下标不在L-R的区间,可以增大R。
代码如下:
#include <cstdio>
#include <map>
using namespace std;
const int maxn = 100;
int A[maxn], last[maxn];
map<int, int> cur;
int main(){
int n;
printf("序列长度n:");
scanf("%d",&n);
cur.clear();
printf("序列:");
for(int i = 0; i < n; i++) {
scanf("%d",A+i);
if(!cur.count(A[i])) last[i] = -1; //-1表示不存在相同的元素
else last[i] = cur[A[i]]; // 记录上一个相同元素的下标
cur[A[i]] = i;
}
int L = 0, R = 0, ans = 0;
while(R < n){
while(R < n && last[R]<L) R++; // last[R]<L表示上一个相同元素的下标不在L-R的区间
ans = max(ans, R-L);
L++;
}
printf("连续子序列长度:%d",ans);
return 0;
}
测试结果: