JavaScriptで部分列(サブシーケンス)を判定する方法|2つのポインタを使った効率的な実装
2つの文字列 str1 と str2 が与えられたとき、str1 が str2 の部分列であるかどうかを判定する関数を作成する方法を解説します。
部分列(サブシーケンス)とは?
文字列の部分列とは、元の文字列から一部の文字(0個でも構いません)を削除して作られる新しい文字列のことです。このとき、残った文字同士の相対的な順序は崩してはいけないというルールがあります。
例を挙げてみましょう。
"ace"は"abcde"の部分列です(b と d を削除すれば ace になります)。"aec"は"abcde"の部分列ではありません。a → e → c の順に並んでおらず、元の順序が崩れているためです。
実装例:2つのポインタを使うアプローチ
最もシンプルで効率的な方法は、2つのポインタ(インデックス)を使って両方の文字列を一度だけ走査する手法です。
const str1 = 'ace';
const str2 = 'abcde';
const isSubsequence = (str1, str2) => {
let i = 0;
let j = 0;
while (i < str1.length) {
if (j === str2.length) {
return false;
}
if (str1[i] === str2[j]) {
i++;
}
j++;
}
return true;
};
console.log(isSubsequence(str1, str2));
コードの仕組み
このアルゴリズムは次のように動作します。
- ポインタ
iはstr1の位置を、ポインタjはstr2の位置を追跡します。 str1[i]とstr2[j]が一致した場合のみ、iを進めます。- ポインタ
jは毎回必ず1つ進みます。 jがstr2の末尾に到達してもstr1の走査が完了していない場合は、falseを返します。- ループを抜けて
str1のすべての文字が順番通りに見つかった場合は、trueを返します。
計算量
- 時間計算量: O(n) —
str2を最大1回走査するだけです。 - 空間計算量: O(1) — ポインタ2つ分の追加メモリしか使いません。
実行結果
コンソールには以下のように表示されます。
true
"ace" は "abcde" の部分列であるため、正しく true が出力されました。この手法は、文字列照合やエディタの補完機能など、さまざまな場面で応用できる基本的なテクニックです。
-
JavaScriptで特定の文字列の順序に従って文字列を並べ替える方法
問題 2つの文字列 str1 と str2 を第1・第2引数として受け取るJavaScript関数を作成する必要があります。 この関数は、str1 を str2 に含まれる文字の出現順序に従って並べ替えます。 例えば、関数への入力が以下の場合を考えてみましょう。 入力 const str1 = coding; const str2 = gncabdi; 出力 const output = gncdio; 出力の説明 str2 の中で先に現れる文字が優先的に前に配置され、その後に後から現れる文字が続きます。そして最後に、str2 に存在しない残りの文字がそのまま並べられます。 解決のアプローチ
-
JavaScriptで配列をシャッフルし、相手配列に対する勝利数を最大化する方法
問題概要 同じ長さを持つ2つの数値配列 arr1 と arr2 を受け取り、arr1 の要素をシャッフルすることで、arr2 の対応する要素よりも大きい要素の数を最大限に増やすJavaScript関数を作成します。最終的に、シャッフル後の配列を返します。 例えば、次のような入力があった場合を考えてみましょう。 入力: const arr1 = [3, 5, 12, 19]; const arr2 = [2, 9, 3, 12]; 出力: const output = [3, 12, 5, 19]; 出力の説明: シャッフル前の arr1 では、arr2 より大きい対応要素は3つでしたが