2301. 替换字符后匹配

题意分析

2301. 替换字符后匹配 - 力扣(LeetCode)

        这道题是将给一些映射关系,将第二个字符串的某些字符改变后,能够和给定的字符串匹配。说实话不是很难,因为它本质还是两两字符串匹配的题目,只不过第二个字符串针对某个字符可以有更多的选择来和第一个字符串进行匹配。但这就有一个问题,就是题目的字符串长度有5000,而映射关系最长有1000,如果用暴力匹配不加优化,那么最坏情况下每次每个字符都有多种匹配时,时间复杂度为5000*5000*1000=25*10^{9},这绝对会超时。所以我采用了以下方法勉强过关。

算法思路

先看一下暴力算法:

class Solution {
public:
    unordered_map<char,vector<char>> map; 
    bool matchReplacement(string s, string sub, vector<vector<char>>& mappings) {
        for(auto m:mappings){
            map[m[0]].emplace_back(m[1]);
        }
        int m=s.length(),n=sub.length();
        if(!m && !n) return true;
        if(m<n || !m) return false;
        for(int i=0;i<m;i++){
            if(match(s,sub,i)) return true;
        }
        return false;
    }
    bool match(string s,string sub,int i){
        int j=0;
        int m=s.length(),n=sub.length();
        for(;i<m && j<n;i++,j++){
            if(s[i]==sub[j]) continue;
            int find=0;
            if(map.count(sub[j])){
                for(auto ch:map[sub[j]]){
                    if(s[i]==ch){
                        find=1;
                        break;
                    }
                }
            }
            if(!find) return false;
        }
        return j==n;        
    }
};

可以发现如果能少算点某层循环或许就好了。而且注意到有些字符是不存在映射关系的,那么在要匹配的字符串中找的这些字符的位置后,再依据这些位置匹配有多种选择的字符,便能大大减少时间复杂度。

所以

  1.  将有映射关系的字符用空格表示,没有的保持原样,形成一个掩膜字符串
  2. 将该字符串和要匹配的字符串比较,如果遇到空格就直接跳过.如果找到位置便放入数组中
  3. 遍历这些位置,如果符合条件,直接返回true

代码实现

class Solution {
public:
    vector<int> sign;
    unordered_map<char,vector<char>> map;
    bool matchReplacement(string s, string sub, vector<vector<char>>& mappings) {
        int m=s.length(),n=sub.length();
        if(!n && !m) return true;
        if(n>m || !m) return false;
        string tmp;
        for(auto m:mappings){
            map[m[0]].emplace_back(m[1]);
        }
        for(auto ch:sub){
            if(map.count(ch)){
                tmp+=' ';
                continue;
            }
            tmp+=ch;
        }
        // cout<<tmp;
        for(int i=0;i<m;i++){
            bool find=1;
            for(int j=0;i+j<m && j<n;j++){
                if(s[i+j]==tmp[j] || tmp[j]==' ') continue;
                else{
                    find=0;
                    break;
                }
            }
            if(find){
                sign.emplace_back(i);
            }
        }
        for(auto & i:sign){
            if(match(s,sub,i)) return true;
        }
        return false;
    }
    bool match(string s,string t,int i){
        int j=0;
        int n=t.size();
        for(;i<s.size() && j<n;i++,j++){
            if(s[i]==t[j]) continue;
            bool find=0;
            if(map.count(t[j])){
                for(auto & ch:map[t[j]]){
                    if(s[i]==ch){
                        find=1;
                        break;
                    }
                }
            }
            if(!find) return false;
        }
        return j==n;
    }
};

解题总结

这题就是暴力匹配+优化,除了kmp,z函数,针对题意也要想出优化方法,用空间换时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值