一、题目大意
给定一个长度为p的数组,其中可能包含重复元素,找到包含数组所有元素至少一次的连续最短序列长度
二、解题思路
我们可以使用尺取法定义左(left)右(right)两个指针,代表[left,right)为当前有效长度(左闭右开),按照如下思路进行尺取法
1、不断的移动right,直到right=p或者[left,right)中包含数组全部元素至少一次
2、如果right=p,但是[left,right)仍然不包含全部元素至少一次,退出程序
3、记录 result = min (result , res)
4、放大left
在获取输入的时候,可以使用set去重,然后set的大小len就是去重后的数量,可以使用map记录每个元素出现的个数,当right右移时,判断如果有元素右移之前是0变成1了,把sum+1,同时不管sun是否变化,都要更新map里的值,然后不断增大right,直到sum==len
当left右移动时,从map中拿到去掉的元素出现的次数,如果去掉之后这个元素出现了0次,那么sum-1,同时不管sum是否变化,一定要更新map
然后每次sum==len时,更新结果为min(result,right-left)
三、代码
#include <iostream>
#include <set>
#include <map>
using namespace std;
int arr[1000007], n = 0, len = 0, distinctArr[1000007], countArr[1000007], res;
map<int, int> cntMap;
void input()
{
scanf("%d", &n);
res = n;
set<int> distinctSet;
for (int i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
distinctSet.insert(arr[i]);
cntMap[arr[i]] = 0;
}
len = distinctSet.size();
}
void solve()
{
// 我们设置[left,right)为有效范围
int left = 0, right = 0, sum = 0, cnt;
while (left <= right)
{
while (right < n && sum < len)
{
cnt = cntMap[arr[right]];
if (cnt == 0)
{
sum++;
}
cnt++;
cntMap[arr[right++]] = cnt;
}
if (sum < len)
{
return;
}
res = min(res, right - left);
cnt = cntMap[arr[left]];
cnt--;
if (cnt == 0)
{
sum--;
}
cntMap[arr[left++]] = cnt;
}
}
int main()
{
input();
solve();
printf("%d\n", res);
return 0;
}