182競争

すべての良い文字列を見つける

長さnの2つの文字列s1およびs2と、文字列evilを提供します。良い文字列の数を返してください。

適切な文字列の定義は次のとおりです。長さはn、辞書式順序はs1以上、辞書式順序はs2以下で、サブ文字列としてevilを含みません。

答えが大きくなる可能性があるため、答えのペア10 ^ 9 + 7の結果を返してください。

 

例1:

入力:n = 2、s1 = "aa"、s2 = "da"、evil = "b"
出力:51
説明: 'a'で始まる25個の適切な文字列があります: "aa"、 "ac"、 「ad」、...、「az」。「c」で始まる25の適切な文字列もあります:「ca」、「cc」、「cd」、...、「cz」。最後に、 'd'で始まる適切な文字列があります: "da"。
例2:

入力:n = 8、s1 = "leetcode"、s2 = "leetgoes"、evil = "leet"
出力:0
説明:辞書の順序がs1以上でs2以下のすべての文字列は、悪意のある文字列 "leet"で始まります。そのため、適切な文字列はありません。
例3:

入力:n = 2、s1 = "gx"、s2 = "gz"、evil = "x"
出力:2
 

ヒント:

s1.length == n
s2.length == n
s1 <= s2
1 <= n <= 500
1 <= evil.length <= 50
すべての文字列は小文字の英字のみを含みます。

 

/ ** 
 * @param {number} n 
 * @param {string} s1 
 * @param {string} s2 
 * @param {string} evil 
 * @return {number} 
 * 1文字の辞書式順序はアルファベットの前です文字は小さく、アルファベットの後ろの文字は大きい。
 *文字列の辞書式順序が最初の文字から次の文字に比較されます。2つの文字が等しい場合、次の文字が比較されます。
 * 2つの文字が等しくないか、文字列の1つに文字がなくなるまで、長さは長くなります。文字列が大きい。
 * / 

const mod = 10 ** 9 + 7 

let cache = null 

var findGoodStrings = function(n、s1、s2、evil){ 
    / ** 
     * 9ビット、生成された文字列sの最大長は500文字で、必須2 ** 9> 500 
     * 6ビット、邪悪な文字列の最長は
     50、2 ** 6> 50 * leftBound 1ビット
     * rightBound 1ビット
     *合計17ビット、生成されたs文字列の長さはmainTraverです、一致するevilの長さはevilMatch、sの最後の文字です
     *下限と上限で境界付けられているかどうかにかかわらず、それぞれの場合に生成される有効な文字列の数 
     *深度優先トラバーサルの特徴は、トラバーサルが最初のレイヤーから始まり、生成された結果が最後のレイヤーから逆方向に生成されることです。 
     *したがって、キャッシュすべての完全なs文字列を記録し、プレフィックス長はmainTraverです、悪一致の長さはevilMatch、
     * s mainTraverの接頭辞の長さ、evil一致の長さevilMatch、s接頭辞の最後の文字のボーダーs1、s2の上下限として下付き文字mainTravel-1文字
     * 4次元カテゴリ分類統計のsの有効な文字列の数
     *したがって、最後の答えは、sの文字列プレフィックス長mainTravelが0、悪が0の長さに一致し、sの文字列プレフィックスが最後の文字を持つことです
     *上限と下限の両方のカテゴリの下の正当なs文字列の数
     * / 
    cache = new Array(1 << 17).fill(-1)
    return dfs(0、0、n、s1、s2、evil、true、true、computeNext(evil))
}; 
/ ** 
 *深さ優先トラバーサル:
 *解決策は、s1とs2の最初の文字から左から右に最後の文字まで
 トラバースすることです。*位置iの各トラバーサル(iの範囲は[0、n]で、0はトラバーサルがまだ開始されていないことを意味します) 、初期条件です。nはトラバーサルが完了したことを示します)、
 *現在の位置の文字は、to to、
 * i-1で選択さた文字がs1 [i-1]およびs1 [i]と等しいかどうかから、同様に、toはi-1で選択されます 
 文字がに等しいかどうか* s2 [i -1]とs2 [i]が決定されます。
 * i位置の文字を選択するたびに、i位置に移動して生成された文字列で、evilが一致できる長さを決定する必要があります。evilMatchの場合
 *現在生成されている文字列とこの文字列が前に付いている文字列が不正であり、直接0を返すことを示す軽いevil.lengthです。
 * s1がn番目の文字に移動した場合、完全な長さが生成されますnの有効な文字は1を返します。
 *最初の条件は、0番目の文字がs1でトラバースされ、不正な一致の長さが0であり、最後に選択された文字が上限と下限の隣にある(true &&の値がtrueであるため) false値は次の条件によって決定されます)
 * mainTravel最後のdfsによって生成されたs文字列の長さ。最初は0で渡され、初期条件が文字が生成されなかったことを示します
 *最後に生成されたs文字列と一致するevilMatch evilの長さ、初期値も0 
 * n 
 * s1 
 * s2 
 * evilです。これらの4つのパラメーターは説明されていません。豚ではないことは言うまでもありません。
 * leftBound前の位置で選択された文字が下限の隣にあるかどうか、1は下限の隣にあることを意味します0は下限の隣にありません
 * rightBound位置で選択された文字が上限の隣にあるかどうか1上限の隣にある
 *次に、選択された現在の文字が現在悪で比較されている文字と等しくない場合、悪の私の下付き文字が
 現在の選択に続くために次使用します 文字が比較され、実際には、特定の文字を選択して生成されたs文字列を拡張した後、evilと新しく生成された文字列の間の一致の長さが
    わかります
 * /  
関数dfs(mainTravel、evilMatch、n、s1、s2、evil、leftBound、rightBound 、次){//最後のdfsによって生成されたs文字列の場合、evilはすべて一致できます。次に、このsの文字列が前に付いた文字列は不正
    です。// 
    直接0を返します。(evilMatch === evil.length)が0を返す場合、このブランチはこれ以上走査を続ける必要はありません
    //これは、完全なs文字列が生成され、正当であることを意味します
    。Dfsは、(mainTravel === n)return 1 
    let key = generateKey(mainTravel、evilMatch、leftBound、rightBound)
    //の場合DFS は最後までトラバースして初期結果を生成します。カテゴリの組み合わせは1回だけ表示され、重複はありません。したがって、このカテゴリの下のデータがカウントされている場合、
    // 
    (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)
        / ** 
        * evilが現在生成されている文字列と一致できる長さを見つける
        *実際、この質問では、evilMatchは長くなるか、同じままで、短くなりません 
        while((j> 0)&&(evil [j]!== c))j = next [j-1] 
        * /
        let j = evilMatch 
  * /
        if(evil [j] === c)j ++ 
        res + = dfs(mainTravel + 1、j、n、s1、s2、evil、leftBound &&(i === from)、rightBound &&(i === to) 、次に)
        res%= mod 
    } 
    cache [key] = res 
    return res 
} 

//キャッシュ
を生成するキー関数generateKey(mainTravel、evilMatch、leftBound、rightBound){ 
    return(mainTravel << 8)|(evilMatch << 2)| ((leftBound?1:0)<< 1)|(rightBound?1:0)
} 

 / ** 
  *特定の添え字まで、特定のサフィックスと等しいプレフィックスの最大長(自己はカウントしないと等しい) 、
  *つまり、最大長は下付き文字であり、下付き文字+ 1)ではありません。
  *つまり、悪の現在の添え字によって示される文字がメイン文字列の現在の文字と等しくない場合、悪は右側に
  スライドする必要があります。つまり、次の悪がメイン文字列の現在の位置にある文字と値を比較するために使用する添え字 
    n = evil.length
function computeNext(evil){
    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 
}

  

出典:LeetCode
リンク:https ://leetcode-cn.com/problems/find-all-good-strings
著作権は控除ネットワークに属しています。商用転載の正式な許可書に連絡し、非商用転載のソースを示してください。

おすすめ

転載: www.cnblogs.com/zhangzs000/p/12729534.html