Skip to content

Commit 996373f

Browse files
committed
Add solution #1397
1 parent 37ec5ac commit 996373f

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 1,279 LeetCode solutions in JavaScript
1+
# 1,280 LeetCode solutions in JavaScript
22

33
[https://leetcodejavascript.com](https://leetcodejavascript.com)
44

@@ -1066,6 +1066,7 @@
10661066
1394|[Find Lucky Integer in an Array](./solutions/1394-find-lucky-integer-in-an-array.js)|Easy|
10671067
1395|[Count Number of Teams](./solutions/1395-count-number-of-teams.js)|Medium|
10681068
1396|[Design Underground System](./solutions/1396-design-underground-system.js)|Medium|
1069+
1397|[Find All Good Strings](./solutions/1397-find-all-good-strings.js)|Hard|
10691070
1400|[Construct K Palindrome Strings](./solutions/1400-construct-k-palindrome-strings.js)|Medium|
10701071
1402|[Reducing Dishes](./solutions/1402-reducing-dishes.js)|Hard|
10711072
1408|[String Matching in an Array](./solutions/1408-string-matching-in-an-array.js)|Easy|
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* 1397. Find All Good Strings
3+
* https://leetcode.com/problems/find-all-good-strings/
4+
* Difficulty: Hard
5+
*
6+
* Given the strings s1 and s2 of size n and the string evil, return the number of good strings.
7+
*
8+
* A good string has size n, it is alphabetically greater than or equal to s1, it is alphabetically
9+
* smaller than or equal to s2, and it does not contain the string evil as a substring. Since the
10+
* answer can be a huge number, return this modulo 109 + 7.
11+
*/
12+
13+
/**
14+
* @param {number} n
15+
* @param {string} s1
16+
* @param {string} s2
17+
* @param {string} evil
18+
* @return {number}
19+
*/
20+
var findGoodStrings = function(n, s1, s2, evil) {
21+
const MOD = 1e9 + 7;
22+
const memo = new Map();
23+
const evilLPS = computeLPS(evil);
24+
25+
function computeLPS(pattern) {
26+
const lps = new Array(pattern.length).fill(0);
27+
let length = 0;
28+
let i = 1;
29+
while (i < pattern.length) {
30+
if (pattern[i] === pattern[length]) {
31+
length++;
32+
lps[i] = length;
33+
i++;
34+
} else {
35+
if (length !== 0) {
36+
length = lps[length - 1];
37+
} else {
38+
lps[i] = 0;
39+
i++;
40+
}
41+
}
42+
}
43+
return lps;
44+
}
45+
46+
function countValid(pos, evilMatched, bound1, bound2, str1, str2, evilStr, lps) {
47+
if (evilMatched === evilStr.length) return 0;
48+
if (pos === n) return 1;
49+
50+
const key = `${pos}:${evilMatched}:${bound1}:${bound2}`;
51+
if (memo.has(key)) return memo.get(key);
52+
53+
let result = 0;
54+
const start = bound1 ? str1[pos] : 'a';
55+
const end = bound2 ? str2[pos] : 'z';
56+
57+
for (let c = start; c <= end; c = String.fromCharCode(c.charCodeAt(0) + 1)) {
58+
let newEvilMatched = evilMatched;
59+
while (newEvilMatched > 0 && c !== evilStr[newEvilMatched]) {
60+
newEvilMatched = lps[newEvilMatched - 1];
61+
}
62+
if (c === evilStr[newEvilMatched]) {
63+
newEvilMatched++;
64+
}
65+
66+
const newBound1 = bound1 && c === str1[pos];
67+
const newBound2 = bound2 && c === str2[pos];
68+
69+
result = (result + countValid(
70+
pos + 1, newEvilMatched, newBound1, newBound2, str1, str2, evilStr, lps
71+
)) % MOD;
72+
}
73+
74+
memo.set(key, result);
75+
return result;
76+
}
77+
78+
return countValid(0, 0, true, true, s1, s2, evil, evilLPS);
79+
};

0 commit comments

Comments
 (0)