一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
题目描述
定义一个单词的“兄弟单词”为:交换该单词字母顺序(注:可以交换任意次),而不添加、删除、修改原有的字母就能生成的单词。
兄弟单词要求和原来的单词不同。例如: ab 和 ba 是兄弟单词。 ab 和 ab 则不是兄弟单词。
现在给定你 n 个单词,另外再给你一个单词 x ,让你寻找 x 的兄弟单词里,按字典序排列后的第 k 个单词是什么?
注意:字典中可能有重复单词。
数据范围:1≤n≤1000 ,输入的字符串长度满足 1≤len(str)≤10 , 1≤k<n 。
输入描述:
输入只有一行。 首先输入字典中单词的个数n,其次输入n个单词作为字典单词, 然后输入一个单词x,最后输入一个整数k。
输出描述:
第一行输出查找到x的兄弟单词的个数m
第二行输出查找到的按照字典顺序排序后的第k个兄弟单词,没有符合第k个的话则不用输出。
示例1
输入:
3 abc bca cab abc 1
输出:
2
bca
示例2
输入:
6 cab ad abcd cba abc bca abc 1
输出:
3
bca
说明:
abc的兄弟单词有cab cba bca,所以输出3
经字典序排列后,变为bca cab cba,所以第1个字典序兄弟单词为bca
题目主要信息
- 兄弟单词定义为:仅交换该单词字母顺序任意次,生成的单词
- 兄弟单词要求与原单词不同
- 现给定n个单词,另外再给一个单词str,寻找上面n个单词中str的兄弟单词里,按字典序排列后的第k个单词
- 先输出兄弟单词个数,不足kkk个兄弟单词则不输出单词
## 排序判断
具体做法:
我们用vector保存输入的全部单词,然后遍历这个vector,对每一个单词判断是否是str的兄弟单词,如果是加入我们的兄弟单词数组中。最后对兄弟单词数组进行排序,即可得到字典序的升序,然后输出这个vector数组的大小,超过k的再输出第k项。
判断两个单词是否是兄弟单词时,我们首先看长度是否一样,长度一样才有可能,然后看是否是相同的字符串,相同字符串则不是兄弟单词,最后我们对两个字符串分别以各自的字符排序,这样两个字符串都是一样的顺序,只要字符集和各个字符数量对得上,排序出来的单词应该是一样的,这就是兄弟单词。
#include<bits/stdc++.h>
using namespace std;
bool isbrother(string s1, string s2){ //查看是否是兄弟单词
if(s1.length() == s2.length()){ //兄弟单词一定要长度相等
if(s1 == s2) //不能是同一个
return false;
sort(s1.begin(), s1.end()); //对两个字符串按字符字典序排序
sort(s2.begin(), s2.end());
if(s1 == s2) //排序后一样才是改变位置能办到的
return true;
}
return false;
}
int main(){
int n;
while(cin >> n){
vector<string> strs(n);
for(int i = 0; i < n; i++) //输入n个字符串
cin >> strs[i];
string str;
cin >> str; //字符串str
int k;
cin >> k;
vector<string> brothers;
for(int i = 0; i < n; i++){ //检查每个字符串是否是兄弟单词
if(isbrother(str, strs[i]))
brothers.push_back(strs[i]);
}
sort(brothers.begin(), brothers.end()); //对后续排序
cout << brothers.size() << endl;
if(brothers.size() >= k) //输出第k个
cout << brothers[k - 1] << endl;
}
return 0;
}
复杂度分析:
- 时间复杂度:O(nlog2n+nmlog2m),其中n为单词总数,m为最大单词的长度,二者大小未知不可消除低次幂。判断函数外主要复杂度就是对brothers数组排序,这个数组最长就是单词总数,判断函数重要是对每个字符串内部排序,一共进行n次
- 空间复杂度:O(n),记录兄弟单词的字符串数组长度最大为n
哈希表判断
具体做法:
判断函数外与方法一相同,但是判断部分我们可以借助无序哈希表,找到两个字符串的字符集和每个字符出现的次数,然后遍历第一个哈希表,如果能在第二个哈希表中找到相同的字符,且二者的value值都相同,则认为这个字符串出现的都一样,比较完整个哈希表都相同,则认为是兄弟单词。
#include<bits/stdc++.h>
using namespace std;
bool isbrother(string s1, string s2){
if(s1.length() == s2.length()){ //兄弟单词一定要长度相等
if(s1 == s2) //不能是同一个
return false;
unordered_map<char, int> mp1;
unordered_map<char, int> mp2;
for(int i = 0; i < s1.length(); i++) //将字符串1的所有字符加入哈希表1中统计出现次数
mp1[s1[i]]++;
for(int i = 0; i < s2.length(); i++) //将字符串2的所有字符加入哈希表2中统计出现次数
mp2[s2[i]]++;
auto it = mp1.begin();
while(it != mp1.end()){ //遍历哈希表1
if(mp2.find(it->first) == mp2.end() || mp2[it->first] != it->second){ //在哈希表2中找到表1遍历到的字符且查看value是否一样
return false;
}
it++;
}
return true;
}
return false;
}
int main(){
int n;
while(cin >> n){
vector<string> strs(n);
for(int i = 0; i < n; i++) //输入n个字符串
cin >> strs[i];
string str;
cin >> str; //字符串str
int k;
cin >> k;
vector<string> brothers;
for(int i = 0; i < n; i++){ //检查每个字符串是否是兄弟单词
if(isbrother(str, strs[i]))
brothers.push_back(strs[i]);
}
sort(brothers.begin(), brothers.end()); //对后续排序
cout << brothers.size() << endl;
if(brothers.size() >= k) //输出第k个
cout << brothers[k - 1] << endl;
}
return 0;
}
复杂度分析:
- 时间复杂度:O(nlog2n+nm),中n为单词总数,m为最大单词的长度,二者大小未知不可消除低次幂。判断函数外主要复杂度就是对brothers数组排序,这个数组最长就是单词总数,判断函数都是无序哈希表操作,最大复杂度为O(m),一共进行n次。
- 空间复杂度:O(n),记录兄弟单词的字符串数组长度最大为n,哈希表长度为单词字母集,不会超过52,属于常数。