バケツに触れて逃げる - LeetCode438.文字列内のすべての文字アナグラムを見つける

創造し続け、成長を加速!「ナゲッツデイリー新プラン・10月アップデートチャレンジ」参加7日目、イベント詳細はこちら

トピックの説明

s 2 つの文字列およびが与えられ た場合、 内 の アナグラムの すべての 部分文字列をp検索 し 、これらの部分文字列の開始インデックスを返します。回答が出力される順序は考慮されません。sp

アトピー語とは、同じ文字を並べ替えてできた文字列(同一の文字列を含む)を指します。

例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
复制代码

例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
复制代码

ヒント:

  • 1 <= s.length, p.length <= 3 * 104
  • s そして p 小文字のみ

問題解決のアイデア

アナグラムとは、同じ長さと同じ文字数の文字列を意味します。

簡単な方法は、文字列の文字を数えpsを毎回iのトラバースして、文字s[i]、s[i + 1]...s[i + p.length]列が文字列のアナグラムpであるを確認し、そうであれば文字をアナグラムに変換することです。用語の開始インデックスが結果配列にi追加されます。

では、統計をどのように使用すればよいのでしょうか。

最初はオブジェクトを使用して各文字列をカウントしていましたが、これは遅すぎてタイムアウトになりました。

したがって、配列マッピングの方法が後で使用されます。length26のそれを埋める0と、インデックスは (ASCII コードに従って) 文字を表します。たとえば、文字'a'に対応するは'a'.charAtCode() - 'a'.charAtCode()、つまり0などです。

次に、pマッピングが完了すると、pマッピング配列を取得します。たとえばp=aab、マッピング配列は [2,1,0,0,....0] 21 (24 0) です。

その後、各文字列がトラバースされると、マッピングが実行されます。アナグラムの場合、2 つの配列の対応する同じです . ここでは、単純にtoString()メソッド、2 つの配列の値が文字列に変換された後に等しいかどうかを比較できます。

答え

/**
 * @param {string} s
 * @param {string} p
 * @return {number[]}
 */
var findAnagrams = function(s, p) {
    const ans = [], lens = p.length, mp = trans(p);

    for(let i=0, l = s.length; i<l; ++i) {
        if(trans(s.substr(i, lens).split('')).toString() === mp.toString()) {
            ans.push(i);
        } 
    }
    return ans;
};

const trans = (p) => {
    const mp = new Array(26).fill(0);
    for(const w of p) {
        mp[w.charCodeAt() - 'a'.charCodeAt()]++;
    }
    return mp;
}
复制代码

キャプチャ.PNG

問題解決のアイデア

方法 1 では、各文字列に対して各走査を実行して文字数s.substr(i, lens).split('')を比較しますが、これには特に時間がかかります。実際、トラバースしているときは、減算を使用して実行できます。

繰り返しになりますが、この概念: 2 つの文字列がアナグラムの場合、それらのと長さは等しくなければなりません。

具体的な手順は次のとおりです。

  1. 文字列 に対して文字の配列マッピングpを実行すると、マッピングされた配列は になりcountます。
  2. string をトラバースし、各文字列の先頭と末尾を表すポインタsとポインタを初期化します。leftright
  3. 文字オフセットcount[s[right].chatCodeAt()-'a.charCodeAt()']減算しましょう。負の数が表示された場合は、アナグラムではないことを意味し、元の状態にリセットする。アナグラムの場合、最後まで縮小されたときにすべてのが 0 でなければならず開始添え字が結果配列に追加されます。1countcountright - left - 1 === nleft
  4. 手順 3 を繰り返します

答え

/**
 * @param {string} s
 * @param {string} p
 * @return {number[]}
 */
var findAnagrams = function(s, p) {
    const ans = [], count = new Array(26).fill(0), m = s.length, n = p.length;
    for(const w of p) {
        ++count[w.charCodeAt() - 'a'.charCodeAt()];
    }
    for(let l=0, r=0; r<m; ++r) {
        --count[s[r].charCodeAt() - 'a'.charCodeAt()];
        while(count[s[r].charCodeAt() - 'a'.charCodeAt()] < 0) {
            ++count[s[l].charCodeAt() - 'a'.charCodeAt()];
            l++;
        }
        if(r - l + 1 === n) {
            ans.push(l);
        }
    }
    return ans;
};
复制代码

キャプチャ.PNG

おすすめ

転載: juejin.im/post/7150320640292028446