Pythonで連続する数値の区間を検出するプログラムの書き方
一意な(重複のない)数値のリスト nums が与えられたとします。このとき、nums 内で連続している数値をひとつの包括的な区間としてまとめ、ソート済みの2次元配列として出力することを目標とします。
たとえば、入力が nums = [10, 11, 12, 15, 16, 17, 28, 30] の場合、出力は [[10, 12], [15, 17], [28, 28], [30, 30]] となります。これは、10〜12 と 15〜17 がそれぞれ連続した数値のまとまりである一方、28 と 30 は前後の数値とつながっていないため、単独の区間 [28, 28]、[30, 30] として表現されるためです。
解決のための手順
この問題は、以下のステップで解くことができます。
- リスト
numsを昇順にソートする numsの末尾に十分に大きな値(ここでは 1e9)を挿入し、「番兵」として機能させる- 結果を格納する空のリスト
ansを用意する - 現在の区間の開始位置
lをnums[0]で初期化する - i を 1 から
numsのサイズまで繰り返すnums[i]がnums[i-1] + 1と等しくない場合(連続が途切れた場合)- 区間
[l, nums[i-1]]をansの末尾に追加する lをnums[i]に更新し、新しい区間の開始位置とする
- 区間
- 最後に
ansを返す
ポイントは、末尾に挿入した大きな値が「番兵」として働き、ループの最後で必ず区間を閉じる処理が実行される点です。これにより、最後の区間を別途処理する必要がなくなります。
それでは、実際の実装を見てみましょう。
実装例
class Solution:
def solve(self, nums):
nums.sort()
nums.append(1e9)
ans=[]
l=nums[0]
for i in range(1,len(nums)):
if nums[i] != nums[i-1] + 1:
ans.append([l, nums[i-1]])
l=nums[i]
return ans
ob = Solution()
nums = [10, 11, 12, 15, 16, 17, 28, 30]
print(ob.solve(nums))入力
[10, 11, 12, 15, 16, 17, 28, 30]
出力
[[10, 12], [15, 17], [28, 28], [30, 30]]
計算量について
このアルゴリズムの時間計算量は O(n log n) です。全体の処理の中でソートが支配的なコストとなるためです。ソート済みのリストが与えられている場合は、線形時間 O(n) で処理できます。また、空間計算量は結果を格納するための O(n) となります。
-
Pythonで配列(リスト)の合計を求める方法をわかりやすく解説
この記事では、配列(リスト)の合計値を求めるという問題に対して、Pythonでの解決策とアプローチをわかりやすく解説します。 問題の定義 配列が入力として与えられたとき、その配列に含まれるすべての要素の合計を計算することを目標とします。 例えば、[1, 2, 3, 4, 5] という配列が与えられた場合、出力は 15 になります。 アプローチ1:ループを使った素朴な方法(総当たり法) 最も基本的な方法は、リストを先頭から順に走査し、各要素を合計用の変数に加算していくやり方です。手順は以下の通りです。 合計を格納する変数を 0 で初期化します。 for ループでリストの各要素を取り出し、順番に
-
Pythonで配列内の最大要素を見つける方法【初心者向け解説】
本記事では、配列の中から最大の要素を見つけるための解法とアプローチについて詳しく解説します。 問題の概要 配列が入力として与えられたとき、その中から最も大きい要素を見つけ出すことが課題となります。 アプローチ この問題は「線形探索」と呼ばれるシンプルな手法で解決できます。手順は以下の通りです。 まず、変数 max を配列の最初の要素で初期化します。 次に、2番目の要素から配列の末尾まで順番に走査していきます。 走査中の各要素について、現在の max の値と比較します。 要素が max より大きければ、max の値をその要素で更新します。 そうでなければ、そのまま次の要素へ進みます。 この処