Pythonで重なる区間をマージし、昇順に並べ替える方法
問題の概要
区間(インターバル)のリストが与えられたとき、それらを統合(マージ)し、ソート済みのシーケンスとして返すことを考えます。
例えば、入力が inv = [[2, 5], [4, 10], [20, 25]] の場合、[2, 5] と [4, 10] は重なっているため [2, 10] にまとめられ、出力は [[2, 10], [20, 25]] となります。
解決の手順
この問題は以下のステップで解くことができます。
- まず、区間のリストを開始位置を基準にソートします。これにより、マージ対象となる区間が必ず隣接するようになります。
- 結果を格納するための新しいリスト
ansを用意します。 - ソート済みの各区間 (s, e) について次の処理を行います。
ansが空でなく、現在の区間の開始位置 s がansの最後の区間の終了位置以下である場合(=区間が重なっている場合)、最後の区間の終了位置を「現在の終了位置 e と既存の終了位置の最大値」で更新します。- それ以外の場合(=区間が重なっていない場合)、新しい区間 [s, e] を
ansに追加します。
- 最後に
ansを返します。
このアルゴリズムの計算量は、ソート部分が O(n log n)、マージ処理が O(n) となり、全体として O(n log n) で効率的に動作します。
実装例
以下のコードで実際の動作を確認してみましょう。
class Solution:
def solve(self, intervals):
intervals.sort()
ans = []
for s, e in intervals:
if ans and s <= ans[-1][1]:
ans[-1][1] = max(ans[-1][1], e)
else:
ans.append([s, e])
return ans
ob = Solution()
inv = [[2, 5], [4, 10], [20, 25]]
print(ob.solve(inv))入力
[[2, 5], [4, 10], [20, 25]]
出力
[[2, 10], [20, 25]]
コードのポイント
- ソートが鍵: 区間を開始位置でソートしておくことで、現在の区間と比較すべき相手は常に
ansの末尾の区間だけでよくなります。 - 包含関係への対応:
max(ans[-1][1], e)を使うことで、ある区間が別の区間に完全に含まれるケース(例:[2, 10] の後に [3, 5] が来る場合)でも正しく処理できます。 - 隣接する区間: 「s == 前の区間の終了位置」も条件
s <= ans[-1][1]に含まれるため、[1, 3] と [3, 5] のような端点で接する区間も [1, 5] にマージされます。接する区間を別々に扱いたい場合は、条件をs < ans[-1][1]に変更してください。
-
【Python】再帰を使わない反復型(ボトムアップ)マージソートの実装方法を解説
この記事では、反復処理(イテレーション)のみでマージソートを実装する方法について解説します。再帰呼び出しを使わずに、whileループだけで配列を整列させる「ボトムアップ方式」のアプローチを見ていきましょう。 問題文 問題: 与えられた配列を、反復処理によるマージソートの考え方を用いて昇順に並べ替えてください。 例として、次の整数配列を扱います。 a = [2, 5, 3, 8, 6, 5, 4, 7] 反復マージソートの考え方 通常のマージソートは再帰を使って配列を分割しますが、反復版では最初から要素数1の部分配列として捉え、隣接する部分配列同士を統合(マージ)しながらサイズを倍々に増やしてい
-
Pythonで学ぶ選択ソートの基本原理と実装方法をわかりやすく解説
本記事では、選択ソート(Selection Sort)の基本的な仕組みと、Python 3.xでの実装方法について詳しく解説します。 選択ソートとは? 選択ソートは、ソートされていない部分から最小値の要素を繰り返し見つけ出し、それを先頭に移動させることで配列全体を整列していくアルゴリズムです。処理の過程では、与えられた配列が次の2つの部分配列に分けられます。 すでにソートが完了している部分配列 まだソートされていない部分配列 選択ソートの各イテレーション(反復処理)では、未ソート部分から最小要素を取り出し、ソート済み部分の末尾に挿入していきます。この操作を繰り返すことで、最終的に配列全体