1
const mod = 10 ** 9 + 7;12
var findGoodStrings = function (n, s1, s2, evil) {15
* - 9 bit: 2 ** 9 > 500 by evil16
* - 6 bit: 2 ** 6 > 50 by evil17
* - 1 bit left (bound)18
* - 1 bit right (bound)20
* cache: `mainTraver` is the prefix length, `evilMatch` is matching for evil22
* answer: marnTravel 0, evil 0, s prefix has the last character24
cache = new Array(1 << 17).fill(-1);25
return dfs(0, 0, n, s1, s2, evil, true, true, computeNext(evil));29
* 1. loop from `s1` to `s2`, range of position `i` is [0, n]: 0 means no start, n means complete30
* 2. if `s1` has traversed to nth, it means has been generated a legal character, and return 1; else31
* 3. `mainTravel` is the length of the `s` generated by dfs last time32
* 4. `evilMatch` is the length that matches the last generated `s` in evilMatch evil33
* 5. n, s1, s2, evil, left, right, next47
// same length means that the match has been successful48
if (evilMatch === evil.length) {51
// this means s is conformed52
if (mainTravel === n) {57
let key = generateKey(mainTravel, evilMatch, left, right);58
// because any combination of the four categories will only appear once, there will be no repetition59
if (cache[key] !== -1) {63
// get start, end calculate65
left ? s1.charCodeAt(mainTravel) : 97,66
right ? s2.charCodeAt(mainTravel) : 122,70
for (let i = start; i <= end; i++) {72
let code = String.fromCharCode(i);73
// actually, `evilMatch` will only get longer or stay the same, not shorter76
while (m > 0 && evil[m] !== code) {80
if (evil[m] === code) {101
// result after cache set102
return (cache[key] = ans), ans;105
// create key for cache106
function generateKey(mainTravel, evilMatch, left, right) {110
((left ? 1 : 0) << 1) |115
// for next right move, index + 1116
function computeNext(evil, n = evil.length, ans = new Array(n).fill(0), k = 0) {117
for (let i = 1; i < n; i++) {118
while (k > 0 && evil[i] !== evil[k]) {122
if (evil[i] === evil[k]) {