map容器在解决“找不同“问题的处理技巧---蓝桥双周之织女的考验

题目:

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人生

哇,真的好可爱(◕ᴗ◕✿)

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值