原题目:https://leetcode-cn.com/problems/pattern-matching-lcci/
思路:
假设p的长度为lp.v的长度为lv,在p中,有ca个a,那么对应的就有(lp - ca)个b,又假设a对应的字符串的长度为la,b对应的字符的长度为lb。对此我们可以得到:
ca*la + (lp-ca)*lb = lv
我们可以对la进行枚举(ca的取值范围为[0,lp/ca],左边界对应空串,右边界对应b为空串),在根据上去算出lb的长度(整数),然后在根据pattern和value把对应的a和b找出来,如果前后对应一致,并且ab不相同,就是有效的。
细节,如果a出现的次数为0,我们就无法对la进行枚举,而换一种思路,我们可以对lb进行枚举,那么我们可以根据对称性,如果a出现的次数小于b,就交换ab,这样不改变我们的结果。
实现逻辑:
1、保证a是出现的次数多的那个字母(上述的细节分析)
2、如果v为空,那么p为空或者一种字符(空串),匹配成功
3、如果p为空,v为空才可以匹配成功
4、如果pv均不为空,那么我们就根据上述的思路进行枚举
代码:
class Solution {
public:
bool patternMatching(string pattern, string value) {
int count_a = 0, count_b = 0;
for (char ch: pattern) {
if (ch == 'a') {
++count_a;
} else {
++count_b;
}
}
//保证a是出现次数多的字母
if (count_a < count_b) {
swap(count_a, count_b);
for (char& ch: pattern) {
ch = (ch == 'a' ? 'b' : 'a');
}
}
//v是空,那么a为空或者只有a( 等价于 b出现的次数为0),
if (value.empty()) {
return count_b == 0;
}
//p为空,而v不为空,匹配失败
if (pattern.empty()) {
return false;
}
for (int len_a = 0; count_a * len_a <= value.size(); ++len_a) {
int rest = value.size() - count_a * len_a;
if ((count_b == 0 && rest == 0) || (count_b != 0 && rest % count_b == 0)) {
int len_b = (count_b == 0 ? 0 : rest / count_b);
int pos = 0;
bool correct = true;
string value_a, value_b;
for (char ch: pattern) {
if (ch == 'a') {
string sub = value.substr(pos, len_a);
if (!value_a.size()) {
value_a = sub;
}
// 前后的a不一致
else if (value_a != sub) {
correct = false;
break;
}
pos += len_a;
}
else {
string sub = value.substr(pos, len_b);
if (!value_b.size()) {
value_b = sub;
}
//前后的b不一致
else if (value_b != sub) {
correct = false;
break;
}
pos += len_b;
}
}
// 匹配成功,并且ab不等
if (correct && value_a != value_b) {
return true;
}
}
}
return false;
}
};