JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptで2つの区間配列の共通部分を求める方法【2ポインタ法】

問題概要

本記事では、2つの区間(インターバル)配列を受け取り、その共通部分を返すJavaScript関数を実装します。入力となる配列 arr1arr2 には以下の前提があります。

  • 各区間は互いに重なり合わない(pairwise disjoint)
  • 各区間はソートされた順序で格納されている

閉区間 [a, b](a ≤ b)は、a ≤ x ≤ b を満たす実数 x の集合を表します。また、2つの閉区間の共通部分(積集合)は、空集合になるか、あるいは1つの閉区間として表現できます。例えば、[1, 3] と [2, 4] の共通部分は [2, 3] です。

入力例

const arr1 = [[0,2],[5,10],[13,23],[24,25]];
const arr2 = [[1,5],[8,12],[15,24],[25,26]];

期待される出力

const output = [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]];

アプローチ:2ポインタ法

両配列がすでにソートされているため、2ポインタ(Two Pointers)法を使えば O(n + m) の時間計算量で効率的に解けます。考え方は以下のとおりです。

  1. 各配列の先頭にポインタ ij を置きます。
  2. 現在注目している区間 A[i] = [a, b] と B[j] = [c, d] に対して、共通部分の下限 lo = Math.max(a, c)、上限 hi = Math.min(b, d) を計算します。
  3. lo ≤ hi が成り立てば共通部分が存在するので、[lo, hi] を結果に追加します。
  4. 終点が小さい側の区間のポインタを1つ進めます。こうすることで、常に「まだ終わっていない最も左側の区間」を比較対象に保てます。
  5. どちらかの配列を走査し終えたら処理を終了します。

実装コード

const arr1 = [[0,2],[5,10],[13,23],[24,25]];
const arr2 = [[1,5],[8,12],[15,24],[25,26]];

const findIntersection = function (A, B) {
  const res = [];
  let i = 0;
  let j = 0;

  while (i < A.length && j < B.length) {
    const [a, b] = A[i];
    const [c, d] = B[j];

    // 共通部分の候補を計算
    const lo = Math.max(a, c);
    const hi = Math.min(b, d);

    if (lo <= hi) {
      res.push([lo, hi]);
    }

    // 終点が小さい側のポインタを進める
    if (b < d) {
      i++;
    } else {
      j++;
    }
  }

  return res;
};

console.log(findIntersection(arr1, arr2));

実行結果

[
  [ 1, 2 ],
  [ 5, 5 ],
  [ 8, 10 ],
  [ 15, 23 ],
  [ 24, 24 ],
  [ 25, 25 ]
]

出力の読み方

最初の区間ペアでは、[0, 2] と [1, 5] の共通部分が [1, 2] になります。また、[5, 10] と [1, 5] のように端点だけが接する場合は、長さ0の区間 [5, 5] として正しく検出されます。このように、点のみの共通部分も漏れなく取得できるのがこのアルゴリズムの特徴です。

まとめ

  • 時間計算量:O(n + m) — 各ポインタは最大でも配列の長さ分しか進みません。
  • 空間計算量:O(1)(出力を除く)— 結果配列以外に追加のメモリは不要です。
  • 実装のポイント:ソート済み・非重複という前提があるため、事前のマージやソートが不要で、シンプルなループだけで実装できます。
  1. JavaScriptのconst宣言とは?再代入できない変数の基本と使い方を解説

    JavaScriptのconst宣言は、値を再代入することも後から再宣言することもできない変数を作成するための構文です。constはES2015(ES6)で導入されました。 const宣言の主な特徴 一度値を代入すると、別の値に再代入することはできません。 同じ名前の変数を同じスコープ内で再宣言するとエラーになります。 宣言時に必ず初期値を代入する必要があります。 ブロックスコープ({}内でのみ有効)を持ちます。 それでは、JavaScriptにおけるconst宣言の実際のコードを見ていきましょう。 サンプルコード <!DOCTYPE html> <html>

  2. JavaScriptで昇順ソートされた3つの配列の共通要素(積集合)を効率的に求める方法

    はじめに本記事では、JavaScriptを使って「昇順にソートされた3つの整数配列」を受け取り、その3つすべてに存在する要素だけを抽出した新しい配列を構築して返す関数の実装方法を解説します。配列がそれぞれソート済みであるという前提を活かせば、全件を比較する非効率な方法ではなく、3つのポインタ(インデックス)を同時に進めていく三方向マージ的な手法で、線形時間 O(n) で共通要素を見つけることができます。問題の概要要件は以下のとおりです。引数として、昇順にソートされた整数の配列を3つ受け取る3つの配列すべてに出現する要素のみを含む配列を返す入力例const arr1 = [4, 7, 8, 11