问题描述
Eureka灰常喜欢吃小浣熊干脆面(五香牛肉味,烤肉味,奇奇怪怪味,意大利红烩味,照烧猪排味,香辣蟹味,海苔味,麻辣香锅味,巧克力味,草莓味,玉米味,炸鸡味,奥尔良烤鸡翅味)。以上只是为了馋一下你 ^_^
现在Eureka厌倦了吃干脆面,所以他打算收集齐所有种类的干脆面送给NONO~,但是新一的自动售货机只能买连续的一些干脆面,你能告诉他最少买多少包么?
输入
第一行两个整数n(1 <= n <= 1000000),表示售货机有连续的n袋干脆面, m(1 <= m <= 2000), 表示一共有m种干脆面
第二行有n个整数分别为a1,a2,a2...,an(1 <= ai <= 2000),表示第i袋干脆面是第ai种的
输出
一个整数ans,表示最少购买多少袋(也就是说最短的区间包含1到m所有类型的干脆面,当然Eureka可以等待别人买完前面的一部分再开始买)
样例中Eureka会选择购买5 3 1 3 2 4这一段共6袋
大致思路:
运用队列的思路来写,开始的时候先把一个包含所有种类的面面的序列读进队列里面,然后依次向后读数字,每读一个数字就从队列头删去相应的重复的数字。
具体实现:
设一个数组用作队列,在一开始的时候把一个包含所有种类面面的数串读进队列里面,并记录每种面面出现的次数(为了后面的删操作)。然后就是一个一个的读数字,读一个数字,将这个数字的出现次数加一,然后从队列的最前面开始搜索,如果该元素出现的次数大于1就将该元素从队列里面删去,并将该元素的出现次数减一,直到找到一个仅在队列里面出现一次的元素为止。此时利用队列头尾指针来计算队列的长度,更新符合要求的最短长度。就这样直到读完所有的元素之后,输出最短长度即可。
注意事项:
(1)进队列出队列的时候相应指针的变化。
(2)进出队列的时候相应面面出现次数的变化。
实现代码
<span style="font-family:Microsoft YaHei;font-size:14px;">#include<stdio.h>
#include<string.h>
int a[1000010],b[1000010];
int main()
{
int n,m;
int i,j,k;
//int a[1000010];
// int b[1000010];
int c[2005];
int start,end,temp,count;
int min=1000010;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
start=0;
end=0;
count=0;
for(i=0;count<m;i++)
{
b[end]=a[i];
end++;
if(c[a[i]]==0)
{
count++;
}
c[a[i]]++;
}
for(j=start;c[b[start]]>1;j++)
{
c[b[start]]--;
start++;
}
temp=end-start;
if(temp<min)
{
min=temp;
}
for(k=i;k<n;k++)
{
b[end]=a[k];
end++;
c[a[k]]++;
// if(b[start]==a[k])
// {
for(j=start;c[b[start]]>1;j++)
{
c[b[start]]--;
start++;
}
// }
temp=end-start;
if(temp<min)
{
min=temp;
}
}
printf("%d\n",min);
return 0;
}</span>