182 Competition

Find all good strings

Gives you two strings s1 and s2 of length n, and a string evil. Please return the number of good strings.

The definition of a good string is: its length is n, the lexicographic order is greater than or equal to s1, the lexicographic order is less than or equal to s2, and it does not contain evil as a substring.

Since the answer may be large, please return the result of the answer pair 10 ^ 9 + 7.

 

Example 1:

Input: n = 2, s1 = "aa", s2 = "da", evil = "b"
Output: 51
Explanation: There are 25 good strings beginning with 'a': "aa", "ac", "ad", ..., "az". There are also 25 good strings starting with 'c': "ca", "cc", "cd", ..., "cz". Finally, there is a good string starting with 'd': "da".
Example 2:

Input: n = 8, s1 = "leetcode", s2 = "leetgoes", evil = "leet"
Output: 0
Explanation: All strings whose dictionary order is greater than or equal to s1 and less than or equal to s2 start with the evil string "leet" . So there is no good string.
Example 3:

Input: n = 2, s1 = "gx", s2 = "gz", evil = "x"
Output: 2
 

prompt:

s1.length == n
s2.length == n
s1 <= s2
1 <= n <= 500
1 <= evil.length <= 50
All strings contain only lowercase English letters.

 

/ ** 
 * @param {number} n 
 * @param {string} s1 
 * @param {string} s2 
 * @param {string} evil 
 * @return {number} 
 * The lexicographic order of a single letter is in front of the alphabet The letters are small, and the letters behind the alphabet are large. 
 * The lexicographic order of the string is compared from the first character to the next one, if the two characters are equal, then the next one is compared; 
 * Until the two characters are not equal or one of the strings does not have more letters, then the length is large String is large. 
 * / 

const mod = 10 ** 9 + 7 

let cache = null 

var findGoodStrings = function (n, s1, s2, evil) { 
    / ** 
     * 9 bits, the generated string s has a maximum length of 500 characters, required 2 ** 9> 500 
     * 6 bits, the longest length of evil string is 50, 2 ** 6> 50 
     * leftBound 1 bit 
     * rightBound 1 bit 
     * total 17 bits, the length of the generated s string is mainTraver , The length of matching evil is evilMatch, the last character in s 
     * The number of legal strings generated in each case whether they are bordered by the lower and upper bounds 
     * The feature of depth-first traversal is that the traversal starts from the first layer, but the generated result is generated backwards from the last layer. 
     * So the cache records all the complete s strings that have been generated, and the prefix length is mainTraver , Evil match length is evilMatch, 
     * prefix length of s mainTraver, evil matched length evilMatch, s prefix last character borders s1, s2 with subscript mainTravel-1 characters as upper and lower bounds 
     * four dimensions The number of s legal strings for category classification statistics 
     * So the final answer is that the s string prefix length mainTravel is 0, evil has matched the length of 0, and the s string prefix has the last character 
     * The legal s under the category that both upper and lower boundaries Number of strings 
     * / 
    cache = new Array (1 << 17) .fill (-1) 
    return dfs (0, 0, n, s1, s2, evil, true, true, computeNext (evil)) 
}; 
/ ** 
 * Depth-first traversal: 
 * The solution is to traverse from the first character of s1 and s2 from left to right to the last character 
 * Each traversal of a position i (the range of i is [0, n], 0 means that traversal has not yet started , Is the initial condition, n indicates that the traversal is completed), 
 * The character at the current position can be changed from from To to, from 
 whether the character selected by * i-1 is equal to s1 [i-1] and s1 [i], similarly, to is selected by i-1
 * Whether the character is equal to s2 [i -1] and s2 [i] is determined.  
function dfs (mainTravel, evilMatch, n, s1, s2, evil, leftBound, rightBound , next) {
 * Every time you select a character in i position, you must determine the length that evil can match in the character string generated by traversing to i position. If evilMatch
 * The light evil.length, indicating that the currently generated string and the string prefixed with this string are illegal, and directly returns 0 
 * If s1 has traversed to the nth character, it means that a complete length is generated The legal character of n returns 1. 
 * The initial condition is that the 0th character is traversed in s1, the length of the evil match is 0, and the last selected character is next to the upper and lower bounds (because true && any value is true The false value is determined by the following conditions) 
 * mainTravel The length of the s string generated by the last dfs, initially passed in 0, indicating that the initial condition is that no character was generated 
 * The length of the evilMatch evil that matches the last generated s string, The initial value is also 0 
 * n 
 * s1 
 * s2 
 * evil, these four parameters are not explained, it is needless to say that they are not pigs 
 * leftBound Whether the character selected at the previous position is next to the lower bound, 1 means that it is next to the lower bound 0 is not next to the lower bound 
 * rightBound Whether the character selected in a position is next to the upper boundary 1 next to the upper boundary 
 * next, if the current character selected is not equal to the character currently being compared in evil, which subscript character in evil I will use next 
 to follow the current selection The characters are compared, in fact, you get the length of the match between evil and the newly generated string after selecting a certain character to extend the generated s string 
 * / 
    // directly return 0, this branch does not need to continue traversing anymore 
    if (evilMatch === evil.length) return 0
    // If the last s string generated by dfs can be matched by evil, then the string prefixed with this s string is illegal, 
    // This means that a complete s string is generated and is legal, and dfs traverses to the end Generate initial result 
    if (mainTravel === n) return 1 
    let key = generateKey (mainTravel, evilMatch, leftBound, rightBound) 
    // Because any combination of the four categories will only appear once, there will be no duplication, so if it has been counted Well, the data under this category 
    // then you can directly reuse the previous results 
    if (cache [key]! == -1) return cache [key] 
    let from = leftBound? S1.charCodeAt (mainTravel): 97 
    let to = rightBound? s2.charCodeAt (mainTravel): 122 
    let res = 0 
    for (let i = from; i <= to; i ++) { 
        let c = String.fromCharCode (i) 
        / ** 
        * Find evil and the current generated The length that the string can match 
        * In fact, in this question, evilMatch will only become longer or remain the same, not shorter 
        * /
        let j = evilMatch  
        while ((j> 0) && (evil [j]! == c)) j = next [j-1]
        if (evil [j] === c) j ++ 
        res + = dfs (mainTravel + 1, j, n, s1, s2, evil, leftBound && (i === from), rightBound && (i = == to), next) 
        res% = mod 
    } 
    cache [key] = res 
    return res 
} 

// key 
function to generate cache generateKey (mainTravel, evilMatch, leftBound, rightBound) { 
    return (mainTravel << 8) | (evilMatch < <2) | ((leftBound? 1: 0) << 1) | (rightBound? 1: 0) 
} 

 / ** 
  * Until a certain subscript, the maximum length of the prefix equal to a certain suffix (self Equal to oneself does not count, 
  * that is the maximum length is subscript, not subscript + 1). 
  * That is, if the character indicated by the current subscript of the evil is not equal to the current character in the main string, evil has to 
  slide to the right * how many positions. That is, which subscript the next evil uses to compare the value with the character at the current position in the main string 
  * / 
function computeNext (evil) { 
    let n = evil.length
    let arr = new Array(n).fill(0)
    arr[0] = 0
    let j = 0
    for(let i = 1; i < n; i++) {
        while((j > 0) && (evil[i] !== evil[j])) j = arr[j - 1]
        if(evil[i] === evil[j]) arr[i] = ++j
        
    }
    return arr
}

  

Source: LeetCode
Link: https://leetcode-cn.com/problems/find-all-good-strings The
copyright belongs to the deduction network. Please contact the official authorization for commercial reprint, and please indicate the source for non-commercial reprint.

Guess you like

Origin www.cnblogs.com/zhangzs000/p/12729534.html