面试题 16.18. 模式匹配
你有两个字符串,即pattern和value。 pattern字符串由字母"a"和"b"组成,用于描述字符串中的模式。例如,字符串"catcatgocatgo"匹配模式"aabab"(其中"cat"是"a",“go"是"b”),该字符串也匹配像"a"、"ab"和"b"这样的模式。但需注意"a"和"b"不能同时表示相同的字符串。编写一个方法判断value字符串是否匹配pattern字符串。
思路
直接计算pattern字符串中a和b的个数,然后解二元一次方程组:
len_a × count_a + len_b × count_b = value.size()即可,直接枚举len_a即可。
- 枚举时需要注意,count_a不能为0,因而必须保证count_a大于等于count_b。
- pattern为空时,value必须为空。
- value为空时,pattern为空或者只出现一个字母a。
- 当value和pattern都不为空时,枚举len_a来解即可。
代码
class Solution {
public:
bool patternMatching(string pattern, string value) {
int count_a = 0, count_b = 0;
for(const char& ch : pattern) {
if(ch == 'a') {
count_a++;
}
else {
count_b++;
}
}
//保证count_a不小于count_b,否则交换
if(count_a < count_b) {
swap(count_a, count_b);
for(char& ch : pattern) {
ch = (ch == 'a'? 'b' : 'a');
}
}
//value为空时,b为0或者a、b都为0
if(value.empty()) {
return count_b == 0;
}
//value不空,pattern为空时返回false
if(pattern.empty()) {
return false;
}
//枚举len_a,保证len_a * count_a <= value.size(),这样len_b不为负数
for(int len_a = 0; len_a * count_a <= value.size(); len_a++) {
int rest = value.size() - count_a * len_a;
//当count_b为0时,剩余字符只能为0,count_b不为0时,保证len_b为整数
if((rest == 0 && count_b == 0) || (count_b != 0 && rest % count_b == 0)) {
int len_b = (count_b == 0? 0 : rest / count_b);
string value_a, value_b;
int pos = 0;
bool ans = true;
//根据len_a和len_b切割字符串
for(const char& ch : pattern) {
//切割len_a
if(ch == 'a') {
string tmp = value.substr(pos, len_a);
if(value_a.empty()) {
value_a = move(tmp);
}
else {
//上次切割和今次切割不一致则失败
if(value_a != tmp) {
ans = false;
break;
}
}
pos += len_a;
}
//切割len_b
else {
string tmp = value.substr(pos, len_b);
if(value_b.empty()) {
value_b = move(tmp);
}
else {
if(value_b != tmp) {
ans = false;
break;
}
}
pos += len_b;
}
}
//value_a和value_b不能为相同字符串
if(ans && value_a != value_b) {
return true;
}
}
}
return false;
}
};