反片语(UVa 156)

Description:
输入一些单词,找出所有满足如下条件的单词:该单词不能通过字母重排,得到输入文本中的另外一个单词。在判断是否满足条件时,字母不分大小写,但在输出时应保留输入中的大小写,按字典序进行排列(所有大写字母在所有小写字母的前面)
Sample input:
Disk came acMe am

Sample output:
Disk
am
这个是算法竞赛入门经典(第二版)map中的例题,在第113页,自己刚开始看真的看不懂,所以懂了之后就想记录的详细点,或许可以给和我一样有点迷的人一些参考:
首先题目的意思是相同字母组成的单词不论字母顺序和大小写都算同一个单词,输出的应该是用一些字母组成的单词只出现过一次的,比如acme和caMe就是一个单词;
这道题最巧妙的是用动态数组vertor(words)存储上所有输入的单词,然后进行标准化,标准化写成了一个函数,例如将单词caMe标准化后就变成了acem.
用map(cnt)存储标准化后的单词,因为map是映射,可以计算单词个数。

#include<iostream>
#include<cstdio>
#include<cctype>//用到了tolower()函数 
#include<map>//map就是从键key到值value的映射 
#include<algorithm>//用到了sort()函数 
#include<string> //string相当于一个字符数组 
#include<vector>//vector是不定长数组 
using namespace std;
map<string,int> cnt;//cnt存储标准化后的单词 
vector<string> words;//words存储所有的单词 
string  repr(const string &s){//看其他解析说const是为了不改变s的初值,但是我觉得先把原单词存到words中了,应该可以不用,我试着去掉后没问题 
	string ans=s;
	for(int i=0;i<ans.length();i++)
	    ans[i]=tolower(ans[i]);//将单词中所有字母都变为小写字母 
	sort(ans.begin(),ans.end() );//将单词打乱重排,好分析有没有用相同字母组成的单词 
	return ans;
}
int main(){
	int n=0;//不知道这句有什么用,去掉也没发现什么问题
	string s;
	while(cin>>s){
		if(s[0]=='#') break;//遇到#表示输入结束 
		words.push_back(s);//将每个单词都按照原来的形式存入words中 
		string r=repr(s);//单词标准化 
		if(!cnt.count(r)) cnt[r]=0;//cnt.count(r)返回map中r的个数;若没有我们将该单词加入map,个数设置为0; 
		cnt[r]++;//统计每个单词的个数(标准化了) 
	}
	vector<string> ans;
	for(int i=0;i<words.size();i++)//words中的每个单词标准化后去map中查个数 
	    if(cnt[repr(words[i])]==1) ans.push_back(words[i]);//若为1符合题意,没有相同字母组成的其他单词,赋给ans 
	sort(ans.begin(),ans.end());//ans中单词按字典序排序 
	for(int i=0;i<ans.size();i++)
	    cout<<ans[i]<<"\n";
	return 0;
}

啊我真的好啰嗦!看代码不太清楚还是自己举个例子好理解,比如我的输入是Disk came acMe am #
那么words数组中就是这四个元素:Disk came acMe am;
而cnt中的四个元素是:diks acem acem am;(其中cnt[acme]=2,cnt[diks]=1, cnt[am]=1)
ans中的元素就是:Diks am。

猜你喜欢

转载自blog.csdn.net/qq_40486952/article/details/83993848
156