题目:
3.织女的考验【算法赛】 - 蓝桥云课 (lanqiao.cn)
问题描述
七夕节即将到来,七夕城热闹非凡,牛郎想邀约美丽的织女一同前往七夕城漫步。
织女并不想轻易地接受牛郎的邀约,于是向他提出了一个有趣的字符串问题:
- 给定两个长度相等的小写字符串 S 和 T,牛郎需要判断是否可以从 S 和 T 中各删除一个字符,使得删除后的 S 经过重新排列后等于 T。若可以则输出
YES
,否则输出NO
。织女表示,如果牛郎能够回答正确,她就会同意牛郎的邀约。
但是,牛郎不太擅长处理字符串问题,为了抱得美人归,他需要你的帮助来解决这个问题。
输入格式
第一行输入一个整数 t(1≤t≤10^3),表示询问的数量。
接下来 t 行,每行输入两个小写字符串 S,T(1≤∣S∣,∣T∣≤10^3)表示一次询问。
数据保证 ∑i=1t∣S∣ 不超过 10^6。
输出格式
输出 t 行,每行一个整数表示答案,
输入样例
3 aba aac abc ade c d
输出样例
YES NO YES
说明
对于第 3 个查询,操作后 S,T 为空也视为相等。
分析题目:
题目翻译一下,要求比较两字符串的异同,异同不能超过1,且不用关心顺序。那就很适合哈希去记录查找。
想法一:暴力模拟哥
因为每个字符串只有10^3,就算二重循环加10^3个数据也只到10^9,直接二重循环遍历所有可能,然后对每个可能删了或者忽略后对比。但除非删除和对比能做到O(1)级别,不然还会超的,起码现在没见题解中有暴力哥活下来
想法二:哈希记录两字符串出现次数
分支一,26个元素的数组哈希1、哈希2,记录str1、str2中的字母,然后比较哈希1、哈希2是否只存在两个或零个字母差小于1
分支二,同上理,不过优化了一点空间和思路,且使用了map容器------从大佬(肖大温柔吖)题解里发现的
(不过map存入也需要nlogn去排序,完全可以将此思路应用在单纯的哈希数组更快)
分支一解法:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,ans=0;
cin>>n;
while(n--){
string str1,str2;
int has[26]={0},has2[26]={0};
ans=0;
cin>>str1>>str2;
if(str1.length()==1){
cout<<"YES"<<endl;
}
else{
for(int i=0;i<t.length();i++){
has[str1[i]-'a']++;
has2[str2[i]-'a']++;
}
for(int i=0;i<26;i++){
ans+=abs(has[i]-has2[i]); //哈希1、2的差
}
if(ans>2){ //差大于2即可能不止一对字母有差
cout<<"NO"<<endl;
}else{ //正确情况有ans==0 || ans==2,对应全同和1对字母差
cout<<"YES"<<endl;
}
}
}
return 0;
}
分支二(map自实现版):
#include <iostream>
#include<map>
using namespace std;
bool shan(string& a,string& b){
//cout<<a.size()<<endl;
if(a.size()<2)return true; //长度相等
int len=a.size(),tt,jay=0,flag=0;
map<char,int>ab;
for(int i=0;i<len;i++){
ab[a[i]]++; //精妙的map使用方法
ab[b[i]]--;
}
for(auto it=ab.begin();it!=ab.end();it++){
tt=it->second;
if(tt){ //找未被对冲的字母
if(tt>0)jay+=tt; //由于对称,可以单边记录冲过了多少,即为两者差
flag++;
}
}
//cout<<"flag="<<flag<<endl;
if(flag>2 || jay>1)return false; //也可以是( flag==2 && jay==1 )||(!flag),即有两种正确情况:正好差2,都一样的
else return true;
}
int main()
{
int t,i;
string a,b;
cin>>t;
i=t;
while(i--){
cin>>a>>b;
if(shan(a,b))puts("YES");
else puts("NO");
}
return 0;
}
分支二精妙map分析:
string a,b;
cin>>a>>b;
map<char,int>mp;
for(int i=0;i<a.size();i++){
mp[a[i]]++; //精妙的map使用方法
mp[b[i]]--; //a、b两字符串都能输入map容器中,且相互对冲
}
如此只用一个map或者一个哈希数组便可,相互对冲后只用关心残留的非0数值对,
int ans=0,flag=0;
for(auto i=mp.begin();i!=mp.end();i++){
if(i->second){
if(i->second>0){
ans+=abs(i->second); //由于对称,可以单边记录冲过了多少,即为两者差
}
flag++;
}
}
if(ans>1||flag>2){
cout<<"NO\n";
}else{
cout<<"YES\n";
}
也可以是( flag==2 && jay==1 )||(!flag),即有两种正确情况:正好差2,都一样。但 || 执行更快点
我写的时候想不到一点,一直在企图用map实现分支一的哈希数组样式,这就是有ak章大佬的小技巧吗 ヘ(;´Д`ヘ)
大佬源码:3.织女的考验【算法赛】 - 蓝桥云课 (lanqiao.cn)题解--肖大温柔吖处
对了,最后都注意一下0、1个元素的特判
if(a.size()<2)return true; //长度相等
呜呜呜,悲报,鄙人之前的代码没通过全因为想当然的puts("Yes")和("No")了,大意了(;′⌒`)考试时一直没发现,同学们要注意题目要求嘞 〒▽〒
镇楼图:
哦,最近Neuro-Sama入驻B站啦,才发现这小可爱AI,要是之后能找到轻松点的工作o(╥﹏╥)o,训练一下自己的AI感觉很好诶,还可以陪在家的父母聊聊天(o゚▽゚)o ,养赛博女儿,赢IT人生
哇,真的好可爱(◕ᴗ◕✿)