单词选择

Problem Description

我们都知道,学习英语单词最好的方法就是在相应的句子和语言环境中学习。小W最近定下来一个学习单词的计划,他要背n个单词,但他想通过背一篇文章的一段来记住这些单词。
假定现在小W手中有一篇包含m个单词的文章,他想在文章中找出连续的一段,其中包含最多的他所要背的单词(重复的只算一个),并且使这段连续的单词长度最短。这样他就可以用尽量短的时间学习尽可能多的单词了。

Input

输入有多组数据。每组数据的第1行为一个数n(1<=n<=1000),接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词。接下来是一个数m(1<=m<=100000),然后是m行长度不超过10的字符串,每个表示文章中的一个单词。

Output

对于每组数据输出2行,第1行为文章中最多包含的要背的单词数,第2行表示在文章中包含最多要背单词的最短的连续段的长度。

Sample Input

3
hot
dog
milk
5
hot
dog
dog
milk
hot

Sample Output

3
3
 
 
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int n,m;  //n表示要背的单词,m表示文章包含的单词数
char word[1010][15];  //要背的单词列表
int point[1010];  //word数组的索引
int index[100010];  //记录文章中各单词对应单词表中的相应单词的下标
int mark[10010];    //表示当前的区段里各单词的出现次数

int cmp(const void *a, const void *b)  //比较函数,按字典序比较
{
     return strcmp(word[*(int*)a],word[*(int*)b]);
} 

int find(char *s)  //在单词表中查找单词s,放回在单词表中的下标
{
     int first,last,mid,temp;
     first=0;  last=n-1;
     while(first<=last)  //采用二分查找
    {
        mid=(first+last)/2;
        temp=strcmp(s,word[point[mid]]);
        if(temp==0) return mid;   /到就返回下标 
        else if(temp<0) last=mid-1;
        else first=mid+1; 
    }
    return -1;   /不到返回-1 
} 


int main()
{
     //freopen("a.in","r",stdin);
     
     int i;
    char s[20];
    //读入单词表
    while(~scanf("%d",&n))
    {
        for(i=0;i<n;i++) scanf("%s",word[i]);
        //point为word索引,然后对其进行排序,即对要背的单词进行字典排序 
        for(i=0;i<n;i++) point[i]=i;
        qsort(point,n,sizeof(point[0]),cmp);        
        
        //读入文章
        scanf("%d",&m);
        for(i=0;i<m;i++)
        {
            scanf("%s",s);
            index[i]=find(s);  //在单词表里找与文章中这单词一样的单词,记录其下标 
        }    
        memset(mark,0,sizeof(mark)); 
        
         int first=0,last=0,total=0,min=0;
        while(last<m)
        {
            if(index[last]>=0)    //如果此单词在单词表中有相同的 
            {
                if(mark[index[last]]==0)   //如果此单词在文章中第一次出现 
                {
                    total++;
                    min=last-first+1;
                }
                mark[index[last]]++;
            }
            //调整first,产生以last结尾包含最多单词的最短序列
            while(first<=last) 
                if((index[first]>=0&&mark[index[first]]>1)||index[first]<0)
                {
                    mark[index[first]]--;
                    first++;
                }
                else break;
            //比较此序列的长度
            if(last-first+1<min) min=last-first+1;
            last++;  //last每步增1 
        }
        printf("%d\n%d\n",total,min);
    }
     return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值