题意分析
这道题是将给一些映射关系,将第二个字符串的某些字符改变后,能够和给定的字符串匹配。说实话不是很难,因为它本质还是两两字符串匹配的题目,只不过第二个字符串针对某个字符可以有更多的选择来和第一个字符串进行匹配。但这就有一个问题,就是题目的字符串长度有5000,而映射关系最长有1000,如果用暴力匹配不加优化,那么最坏情况下每次每个字符都有多种匹配时,时间复杂度为5000*5000*1000=25*,这绝对会超时。所以我采用了以下方法勉强过关。
算法思路
先看一下暴力算法:
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;
}
};
可以发现如果能少算点某层循环或许就好了。而且注意到有些字符是不存在映射关系的,那么在要匹配的字符串中找的这些字符的位置后,再依据这些位置匹配有多种选择的字符,便能大大减少时间复杂度。
所以
- 将有映射关系的字符用空格表示,没有的保持原样,形成一个掩膜字符串
- 将该字符串和要匹配的字符串比较,如果遇到空格就直接跳过.如果找到位置便放入数组中
- 遍历这些位置,如果符合条件,直接返回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函数,针对题意也要想出优化方法,用空间换时间。