JavaScriptで線形時間O(n)で解く「Two Sum(2つの合計)」問題
問題の概要
最初の引数に数値の配列、2番目の引数に目標の合計値(target)を受け取るJavaScript関数を作成します。
関数は、配列の中から2つの数値(連続していなくても構いません)を選び、その合計が目標値と一致する組み合わせが存在すれば、該当する2つの要素のインデックスを返します。
重要な条件は、この処理を線形時間 O(n)、つまり1回のループ走査で完了させることです。単純な二重ループによる総当たり(O(n²))ではこの条件を満たせないため、より効率的なアプローチが必要になります。
解法のポイント:Mapを使う理由
鍵となるのはMap(ハッシュマップ)の活用です。配列を先頭から1回だけ走査しながら、現在の数値とペアになる数(目標値から現在の数値を引いた値)をキーとしてMapに登録していきます。そして走査中に、すでにMapへ登録済みの数値と一致する要素に出会った時点で、そのインデックスのペアを即座に返します。
この方法なら各要素は最大1回しか参照されないため、全体の時間計算量はO(n)に抑えられます。
コード例
const arr = [1, 3, 5, 7, 9, 11];
const target = 16;
const twoSum = function(arr, target) {
const map = new Map();
for(let i = 0; i < arr.length; i++) {
const num = arr[i];
if(map.get(num) === undefined){
// ペアになる数(補数)と自分のインデックスを登録
map.set(target - num, i);
}else{
// 登録済みの補数が見つかったら答えを返す
return [map.get(num), i];
};
};
};
console.log(twoSum(arr, target));
出力結果
コンソールには次のように表示されます。
[3, 4]
処理の流れを詳しく見る
target = 16 の場合、各ステップでの動作は以下の通りです。
- i = 0(num = 1):Mapに「15 → インデックス0」を登録
- i = 1(num = 3):Mapに「13 → インデックス1」を登録
- i = 2(num = 5):Mapに「11 → インデックス2」を登録
- i = 3(num = 7):Mapに「9 → インデックス3」を登録
- i = 4(num = 9):9 はすでにMapに登録済み(対応するインデックスは3)→
[3, 4]を返却
実際に 7 + 9 = 16 となり、目標値を満たす組み合わせが見つかるため、正しく [3, 4] が返されます。
計算量のまとめ
- 時間計算量:O(n) — 配列を1回走査するだけで完了します
- 空間計算量:O(n) — 最悪ケースでは全要素分のエントリをMapに保持します
-
JavaScriptで2つの二分探索木(BST)のノード値の合計が目標値に一致するか判定する方法
問題 JavaScriptの関数を作成します。この関数は、第1引数として1つ目の二分探索木のルートroot1を、第2引数として2つ目の二分探索木のルートroot2を受け取り、さらに第3引数として整数targetを受け取ります。 この関数は、「1つ目の木の中のあるノード」と「2つ目の木の中のあるノード」の値を足し合わせた結果がtargetと一致するようなペアが存在する場合にのみtrueを返し、存在しない場合はfalseを返す必要があります。 たとえば、次のような入力が与えられたとします。 const target = 23; 2つのBSTの例 この場合の出力は次のようになります。 const
-
Pythonで解く「Two Sum(2つの合計)」問題:ハッシュマップを使った効率的な実装方法
整数の配列が与えられたとき、その中から2つの要素を選び、その合計が指定されたターゲット値と一致するようなインデックスのペアを返す問題を考えてみましょう。これは、アルゴリズム学習やコーディング面接で非常によく知られている「Two Sum(2つの合計)」問題です。ここでは、配列内に必ず一意な解が1つだけ存在するという前提を置きます。つまり、同じターゲットに対して複数のインデックスの組み合わせが存在することはありません。問題の例例として、配列 A = [2, 8, 12, 15]、ターゲットの合計値が 20 である場合を考えます。このとき A[1] + A[2] = 8 + 12 = 20 となるた