JavaScriptで最大2種類の異なる文字を含む最長の文字列の長さを求める方法
問題の概要
JavaScriptで、文字列を引数として受け取る関数を作成します。この関数は、元の文字列から不要な文字を削除し、「最大でも2種類の異なる文字」だけで構成される最長の文字列を作り出します。そして最後に、その文字列の長さを返します。
なお、文字を削除しても残った文字の相対的な並び順は保たれます。そのため、この問題は厳密には連続した「部分文字列」ではなく、「部分列(subsequence)」を求める問題だと言えます。
たとえば、入力文字列が次の場合を考えてみましょう。
const str = 'kjeljsdl';
このとき、期待される出力は次のとおりです。
const output = 4;
理由は、「k」「e」「s」「d」を削除すると「j」「l」「j」「l」だけが残り、これが最大2種類の文字で構成できる最長の並び「jljl」(長さ4)となるためです。
解き方のポイント:出現回数を数えるだけ
一見すると複雑そうな問題ですが、実はとてもシンプルです。削除によって任意の位置の文字を取り除けるため、「残したい2種類の文字」を決めてしまえば、それらの文字は元の文字列に現れた回数ぶんすべて残すことができます。
つまり、答えは次の手順で求められます。
- 文字列に含まれる各文字の出現回数を集計する。
- 出現回数を多い順に並べ替える。
- 文字が2種類以上ある場合は上位2文字の出現回数の合計を、1種類しかない場合はその出現回数を返す。
コード例
上記のアイデアを実装したコードがこちらです。
const str = 'kjeljsdl';
const longestSubstring = (str = '') => {
// 空文字列の場合は 0 を返す
if (!str) {
return 0;
}
// 各文字の出現回数を集計する
const freq = {};
for (const ch of str) {
freq[ch] = (freq[ch] || 0) + 1;
}
// 出現回数を多い順に並べ替える
const counts = Object.values(freq).sort((a, b) => b - a);
// 1種類ならその回数、2種類以上なら上位2つの合計を返す
return counts.length === 1 ? counts[0] : counts[0] + counts[1];
};
console.log(longestSubstring(str));
出力
コンソールには次のように表示されます。
4
計算量について
文字の集計には文字列の長さ n に比例した O(n) の時間がかかり、並べ替えには文字の種類数 m に対して O(m log m) の時間がかかります。したがって全体の計算量は O(n + m log m) となります。扱う文字の種類が英小文字などに限られるケースでは m を定数とみなせるため、実質的に線形時間で高速に処理できます。
-
JavaScriptの正規表現を使って文字列の特定部分を削除する方法
JavaScriptでは、正規表現(RegExp)と replace() メソッドを組み合わせることで、文字列の中から指定した2つの区切り文字に挟まれた部分を簡単に削除できます。基本的な考え方たとえば、括弧「( )」で囲まれたテキストを削除したい場合は、次のような正規表現パターンを使用します。/ *\([^)]*\) */g — 括弧とその中身、および前後の空白にマッチします。\( と \) — 開き括弧と閉じ括弧そのものにマッチします。[^)]* — 閉じ括弧以外の任意の文字列にマッチします。末尾の g フラグ — 文字列内のすべての該当箇所を置換対象にします。サンプルコード以下は、文字列か
-
PythonでK個の異なる文字を含む長さNの部分文字列を抽出する方法
「K個の異なる文字」を含む「長さN」の部分文字列を抽出する必要がある場合、文字列を反復処理しながら、setメソッドを使ってユニークな文字の組み合わせを判定します。 サンプルコード 以下に具体的な実装例を示します。 my_string = Pythonisfun print(The string is : ) print(my_string) my_substring = 2 my_chars = 2 my_result = [] for idx in range(0, len(my_string) - my_substring + 1): if (len(set(my_string[