题解 | #查找兄弟单词#
查找兄弟单词
http://www.nowcoder.com/practice/03ba8aeeef73400ca7a37a5f3370fe68
题意
给定一个字符串str,和一组字符串
寻找在这组字符串中有多少个和str不直接相等,但包含的内容相等的(可以交换字母得到)
这组字符串中满足条件的按照字典序排序,求第k个是哪个字符
方法
朴素实现
本题要3个工作
- 比较相等
- 比较是否可以交换得到
- 对给定字符串排序
我们分别如下实现
- 朴素比较
- 对两个字符串,一个辅助数组标记前一个字符是否匹配,遍历后一个字符串,在前一个字符串中找相同字符
- 内置的sort排序
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,n) for (ll i=a;i<n;i++)
#define pb push_back
bool movable(const string &s0, const string &s1){ // s0 s1 是否能通过交换得到
if(s0.size() != s1.size())return false;
vector<bool> vis(s0.size(),false); // s0 是否匹配
for(auto ch:s1){ // 枚举s1 的字符
bool found = false;
rep(i,0,s0.size()){ // 在s0中找没匹配过的相同字符
if(vis[i])continue;
if(s0[i] == ch){ // 找到对应字符进行匹配
found = true;
vis[i] = true;
break;
}
}
if(!found){
return false;
}
}
return true;
}
int main(){
vector<string> ss = {};
vector<string> sdict = {};
int n;
cin>>n;
rep(i,0,n){
string s;
cin>>s;
ss.pb(s);
}
string str;
cin>>str;
for(auto si:ss){
if(si == str)continue; // 排除相等
if(!movable(str,si))continue; // 不能交换得到
sdict.pb(si);
}
sort(sdict.begin(),sdict.end()); // 字符串排序
cout<<sdict.size()<<endl;
int k;
cin>>k;
if(k<=sdict.size()){
cout<< sdict[k-1]<<endl;
}
return 0;
}
复杂度分析
设 字典中字符串个数为n 字典的字符总长度为∑∣si∣, 查询的str的长度为m,
时间复杂度:
读入的部分显然是O(∑∣si∣+m)
对于每个字符的处理,使用字符和字典内的比较的复杂度最坏情况是O(mn2)
对于字符串排序,最坏是O(m⋅n⋅log(n))
空间复杂度: 空间主要是存储字符串,每个字符串最多被存在两个位置,额外辅助数组最大长度和字符串长度相关,所以空间复杂度为O(∑∣si∣+m)
利用字符串的内部排序后再比较
上面的第2点,我们可以优化
- 如果两个字符串可以交换交换得到,那么当且仅当它们自身按字母排序后的两个字符串是相等的
对于第2点数学证明如下,
- 每个字符串自身内部按照字母顺序排序是唯一的
- 每个字符串与其自身内部按照字母顺序是可以相互转换的
- 综上如果两个字符串可以交换字符得到,那么当且仅当它们自身按字母排序后的两个字符串是相等的
以样例为例
- | cab | ad | abcd | cba | abc | bca | abc(查找的字符串) |
---|---|---|---|---|---|---|---|
排序后 | abc | ad | abcd | abc | abc | abc | abc |
- | 相等 | 相等 | 相等 | 相等 |
其中abc
(本身和查找的字符串也相等,所以忽略)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,n) for (ll i=a;i<n;i++)
#define pb push_back
string sortstr(string s){ // 字符串自身按字母排序
sort(s.begin(),s.end());
return s;
}
int main(){
vector<string> ss = {};
vector<string> sdict = {};
int n;
cin>>n;
rep(i,0,n){
string s;
cin>>s;
ss.pb(s);
}
string str;
cin>>str;
string t = sortstr(str);
for(auto si:ss){
if(si == str)continue; // 排除相等
if(t != sortstr(si))continue; // 最小序和查找的最小序不等
sdict.pb(si);
}
sort(sdict.begin(),sdict.end()); // 字符串排序
cout<<sdict.size()<<endl;
int k;
cin>>k;
if(k<=sdict.size()){
cout<< sdict[k-1]<<endl;
}
return 0;
}
复杂度分析
设 字典中字符串个数为n 字典的字符总长度为∑∣si∣, 查询的str的长度为m,
时间复杂度:
读入的部分显然是O(∑∣si∣+m)
对于每个字符的处理,使用sort对字符内部排序,最坏情况是O(∑∣si∣⋅log(∑∣si∣)),
和查找字符串
比较排序后的内容
,所有位置比较一次,最差情况O(∑∣si∣),
对于字符串排序,最坏是m⋅n⋅log(n)
空间复杂度: 空间主要是存储字符串,每个字符串最多被存在两个位置,所以空间复杂度为O(∑∣si∣+m)