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

Pythonで2つの区間リストの重複部分を見つけて昇順に返す方法


閉区間(closed interval)からなる2つのリストがあるとします。それぞれのリストは単体では区間同士が重複しておらず、開始位置の昇順(非減少順)にソートされています。この記事では、2つのリストに共通して含まれる「重複する区間」をすべて見つけ出し、昇順に並べて返すPythonプログラムを解説します。

たとえば、入力が inv1 = [[50, 100],[190, 270],[310, 330]]inv2 = [[40, 120],[180, 190]] の場合、出力は [[50, 100], [190, 190]] になります。

アルゴリズムの流れ

この問題は、マージ処理などでも使われる「2ポインタ」の考え方を応用すると、各リストを一度だけ走査するだけで解けます。手順は以下の通りです。

  • 結果を格納するための空リスト ans を用意する
  • ポインタ i と j をそれぞれ 0 で初期化する
  • i が A の長さ未満 かつ j が B の長さ未満である間、次を繰り返す
    • start := max(A[i][0], B[j][0])、end := min(A[i][1], B[j][1]) を計算する
    • start <= end のとき、区間 [start, end] を ans に追加する
    • A[i][1] < B[j][1] なら i を1進め、そうでなければ j を1進める
  • ans を返す

なぜこれでうまくいくのか

2つの区間の共通部分は、必ず「開始位置の大きい方」から「終了位置の小さい方」までの範囲になります。start <= end が成り立つときだけ実際の重なりが存在し、その区間が答えとなります。また、終了位置が早い側の区間から処理済みとしてポインタを進めることで、常に現時点で先頭にある2区間どうしを比較し続けられます。

実装上の重要なポイントは、重なりが検出されなかった場合でも必ずどちらかのポインタを進めることです。ポインタの更新を交差判定の中に入れてしまうと、重ならない区間に出会った時点で処理が止まり、無限ループに陥ってしまいます。

実装例

class Solution:
    def solve(self, A, B):
        ans = []
        i = 0
        j = 0
        while i < len(A) and j < len(B):
            start = max(A[i][0], B[j][0])
            end = min(A[i][1], B[j][1])
            if start <= end:
                ans.append([start, end])
            if A[i][1] < B[j][1]:
                i += 1
            else:
                j += 1
        return ans

ob = Solution()
inv1 = [[50, 100],[190, 270],[310, 330]]
inv2 = [[40, 120],[180, 190]]
print(ob.solve(inv1, inv2))

入力

[[50, 100],[190, 270],[310, 330]], [[40, 120],[180, 190]]

出力

[[50, 100], [190, 190]]

計算量

時間計算量は O(n + m) です(n、m はそれぞれのリストに含まれる区間の数)。すべての区間ペアを総当たりで調べる O(n × m) のアプローチに比べ、はるかに効率的です。空間計算量については、出力用のリストを除けば O(1) で済みます。


  1. Pythonで解く「kと-kの両方が存在する最大のkを見つける」問題

    この記事では、Pythonを使って「リスト内に k と -k の両方が存在するような、最大の数 k を見つける」問題の解き方を解説します。 問題の概要 数値のリスト nums が与えられたとき、k と -k がどちらもリスト内に存在するような最大の数 k を求めます。該当する要素が存在しない場合は -1 を返します。 たとえば、入力が [-5, 2, 9, -6, 5, -9] の場合、「9」と「-9」が両方存在するため、答えは 9 となります。 解法のアプローチ この問題は、リストを正の数と負の数に分けてソートし、対応するペアを効率的に探すことで解けます。具体的な手順は以下の通りです。 L

  2. Pythonで複数の区間の共通部分(交差する間隔)を見つける方法

    この記事では、Pythonを使って複数の区間(インターバル)の共通部分を見つけるアルゴリズムを解説します。 問題の概要 各要素が [start, end] の形式で表される区間のリストが与えられます。ここで start は区間の開始時刻、end は終了時刻を意味し、両端を含むものとします。このとき、与えられたすべての区間に共通して含まれる区間(交差部分)を求めるのが目的です。 例えば、入力が次のような場合を考えてみましょう。 [[10, 110], [20, 60], [25, 75]] この場合、3つの区間すべてに共通する範囲は [25, 60] となります。なぜなら、最も遅い開始時刻が