在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感觉效率不是太高,个人觉得用字符串处理其实完全可满足要求。