这个题目一言难尽。一开始写了半天,感觉情况特别复杂,还以为是有规律我自己没找到,或者说分类的依据错了。但是看了一下题解发现也是这种强行分类的方法,于是就接着继续完善自己的思路了。
代码如下:
const patternMatching = (pattern, value) => {
// edge case, if pattern len is 1 then it would always matches
if (pattern.length === 1) {
return true;
}
// there are only `a`s and `b`s in the pattern
// so it would be easire to just treat the first char as our `A`
const charA = pattern[0];
const charB = charA === 'a' ? 'b' : 'a';
const charANum = pattern
.split('')
.reduce((p, char) => char === charA ? p + 1 : p, 0);
const charBNum = pattern.length - charANum;
const valLen = value.length;
// edge case, if pattern is normal yet value is falsy
// then it would always be false
if (charANum !== 0 && charBNum !== 0 && !value) {
return false;
}
// category 1
// if there is only one type of char in the pattern
// then we don't need to figure out which char represents which word.
if (charANum === 0 || charBNum === 0) {
const usableNum = charANum || charBNum;
if (valLen % usableNum !== 0) {
return false;
}
const wordLen = valLen / usableNum;
const word = value.slice(0, wordLen);
let j = 0;
for (let i = 0; i < pattern.length; i++) {
if (value.slice(j, j + wordLen) !== word) {
return false;
}
j += wordLen;
}
return j === valLen;
}
// category 2
// most common cases, `a`s and `b`s appear multiple times.
// yet we can figure out an interval to limit the possible combinations.
const maxNum = Math.min(charANum, charBNum);
// the max lenght of one word would be less or equal than
// total value length devided by the number of char
// which appears less than another
const maxWordLen = Math.floor(valLen / maxNum);
let result = false;
// work out a word;
for (let charALen = maxWordLen; charALen >= 0; charALen--) {
if (result) {
break;
}
const totalCharALen = charALen * charANum;
const totalCharBLen = valLen - totalCharALen;
const possibleCharBLen = totalCharBLen / charBNum;
const charBLen = Math.floor(possibleCharBLen);
if (possibleCharBLen !== charBLen) {
// this combination does not work
continue;
}
// then it it just the tedious work of checking if our assumption works
let wordA = null;
let wordB = null;
let j = 0;
for (let i = 0; i < pattern.length; i++) {
if (wordA === wordB && wordA !== null && wordB !== null) {
break;
}
const currChar = pattern[i];
if (currChar === charA) {
const word = value.slice(j, j + charALen);
if (wordA === null) {
wordA = word;
} else if (wordA !== word) {
break;
}
j += charALen;
} else {
const word = value.slice(j, j + charBLen);
if (wordB === null) {
wordB = word;
} else if (wordB !== word) {
break;
}
j += charBLen;
}
}
result = j === valLen;
}
return result;
};