創造し続け、成長を加速!「ナゲッツデイリー新プラン・10月アップデートチャレンジ」参加7日目、イベント詳細はこちら
トピックの説明
s
2 つの文字列およびが与えられ た場合、 内 の アナグラムの すべての 部分文字列をp
検索 し 、これらの部分文字列の開始インデックスを返します。回答が出力される順序は考慮されません。s
p
アトピー語とは、同じ文字を並べ替えてできた文字列(同一の文字列を含む)を指します。
例 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
小文字のみ
問題解決のアイデア
アナグラムとは、同じ長さと同じ文字数の文字列を意味します。
簡単な方法は、文字列の文字を数えp
、s
を毎回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;
}
复制代码
問題解決のアイデア
方法 1 では、各文字列に対して各走査を実行して文字数s.substr(i, lens).split('')
を比較しますが、これには特に時間がかかります。実際、トラバースしているときは、減算を使用して実行できます。
繰り返しになりますが、この概念: 2 つの文字列がアナグラムの場合、それらの数と長さは等しくなければなりません。
具体的な手順は次のとおりです。
- 文字列 に対して文字の配列マッピング
p
を実行すると、マッピングされた配列は になりcount
ます。 - string をトラバースし、各文字列の先頭と末尾を表すポインタ
s
とポインタを初期化します。left
right
- 文字をオフセット
count[s[right].chatCodeAt()-'a.charCodeAt()']
減算しましょう。負の数が表示された場合は、アナグラムではないことを意味し、元の状態にリセットする。アナグラムの場合、最後まで縮小されたときにすべてのが 0 でなければならず、開始添え字が結果配列に追加されます。1
count
count
right - left - 1 === n
left
- 手順 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;
};
复制代码