用C++STL set解SDNU OJ 1099

在C++的STL中,set是一个较简单较实用的容器
其主要特点有:
1.不限长度
2.自动排序
3.自动去重(即不允许重复插入)
根据这些特点来解一下1099这道题:
1099.前缀判断
Description
给定 n 个字符串,求有多少字符串是其他字符串的前缀。
Input
第一行为一个整数n(1 <= n <= 1000),之后n行,每行一个字符串,字符串只由26个小写字母组成,最大长度为100。
Output
一个整数,有多少字符串是其他字符串的前缀。
Sample Input

5
abcde
ab
bcde
b
cde

Sample Output

2

题目分析:对于输入的字符串,有字符串是其他字符串的前几位,即视为前缀;而如果有重复的字符串,则他们亦互为前缀。
所以对于不重复的字符串,可以先建立一个前缀库,只要输入的字符串能在库中被找到,就可将其视为前缀。
对于重复的字符串,由于他们互为前缀,所以有多少个重复的字符串,就有多少个前缀。
若字符串即重复又是其他不同的字符串的前缀,则要避免重复计入。
代码如下(可能有点蠢。。):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;
int num[1001]={0};//用于对输入的相同下标的重复字符串的种类进行标记
int main()
{
    int  n,i,j;
    int cnt=0;//计数器
    string s,b;
    cin>>n;//输入n个字符串
    vector<string> scope;//字符串库
    set<string> address;//前缀库
    vector<string>::iterator it;
    for(i=0;i<n;i++)
    {
        cin>>s;
        scope.push_back(s);//字符串入库
        for(j=0;s[j+1]!='\0';j++)//从字符串第一个字符到倒数第二个字符
        {
            b=s.substr(0,j+1);//依次截取所有前缀(不包括自身)
            address.insert(b);//前缀入库
        }
    }
    for(it=scope.begin();it!=scope.end();it++)//遍历字符串库
    {
        if(address.find(*it)!=address.end())
        {
            *it="1";
            cnt++;
        }      //依次搜索字符串是否是前缀,并对是前缀的进行标记与计数
    }
//到这一步,所有不重复的样例可以通过,后面是对于重复字符串的特殊处理
    for(i=0;i<scope.size()-1;i++)
    {
        for(j=i+1;j<scope.size();j++)
        {
            if(scope[i]==scope[j] && scope[i]!="1")
            //找到重复字符串的同时避免该字符串已被判定为前缀而重复计入
            {
                scope[j]="1";
                num[i]++;
            }
        }
    }        //这个双层循环是搜索标记并记录所有重复字符串的种类
    for(i=0;i<1001;i++)
    {
        if(num[i]>0)
        {
            num[i]++;
            cnt+=num[i];
        }
    }   //该循环统计重复的,尚未被判定为前缀的字符串种类的数目并计入计数器
    cout<<cnt<<endl;//输出计数器中的结果
    return 0;
}

就这个题而言其实用set感觉效率不是太高,个人觉得用字符串处理其实完全可满足要求。

猜你喜欢

转载自blog.csdn.net/izayoi_w/article/details/78513250