Pythonでソート済み行列からn番目に小さい数を見つける方法
問題の概要
行と列がそれぞれ非減少順(昇順)にソートされた2次元行列が与えられたとき、その中からn番目に小さい数を見つけることを考えます。
例えば、次のような行列が入力されたとします。
| 2 | 4 | 30 |
| 3 | 4 | 31 |
| 6 | 6 | 32 |
このとき n = 4 とすると、出力は 6 になります。
解法のアプローチ
最もシンプルで分かりやすい方法は、行列内のすべての要素を1つのリストに集め、ソートしてからn番目の要素を取り出すことです。手順は以下の通りです。
- 空のリスト lst を用意する
- 行列の各行 i について、その中の各要素 j を lst の末尾に追加していく
- リスト lst をソートする
- lst[n] を返す
実装例
それでは、実際のコードを見てみましょう。
class Solution:
def solve(self, matrix, n):
lst = []
for i in matrix:
for j in i:
lst.append(j)
lst.sort()
return lst[n]
ob = Solution()
matrix = [[2, 4, 30], [3, 4, 31], [6, 6, 32]]
n = 4
print(ob.solve(matrix, n))
入力
matrix = [
[2, 4, 30],
[3, 4, 31],
[6, 6, 32]
]
n = 4
出力
6
よりPythonicな書き方
itertools.chain を使うと、ネストしたループを一行でまとめて書くことができます。
from itertools import chain
class Solution:
def solve(self, matrix, n):
return sorted(chain.from_iterable(matrix))[n]
計算量と効率化のポイント
上記の方法では、行数を m、列数を k とすると、全要素の収集に O(mk)、ソートに O(mk log(mk)) の時間計算量が必要です。データ量が少ない場合は十分実用的ですが、大規模な行列では以下のような代替手段が有効です。
- ヒープを使う方法: heapq モジュールで各行の先頭要素を管理し、最小値をn回取り出すことで O(n log m) で求められます。
- 二分探索を使う方法: 行・列がソートされている性質を活かし、「mid 以下の要素数」を数えながら値の範囲を絞り込むことで、O((m + k) log(最大値 − 最小値)) 程度まで高速化できます。
まずは本記事のシンプルな実装でロジックを理解し、必要に応じて効率的なアルゴリズムへ発展させるのがおすすめです。
-
Pythonでリスト内の最小値を見つける方法を解説
この記事では、リストの中から最小の数値を見つける方法について、具体的なサンプルコードとともに詳しく解説します。問題の概要問題: 数値のリストが与えられたとき、その中に含まれる最も小さい数値を画面に表示すること。この問題を解くアプローチは主に2つあります。ひとつは sort() メソッドを使ってリストを昇順に並べ替え、先頭の要素(インデックス0)を取得する方法。もうひとつは、Pythonに標準で用意されている組み込み関数 min() を使う方法です。それぞれ順番に見ていきましょう。方法1:sort()メソッドで並べ替えて最小値を取得するまずはリストを昇順にソートし、先頭の要素を取り出す方法です。
-
PythonでN番目のカタラン数を計算する方法【再帰・動的計画法】
本記事では、N番目のカタラン数(Catalan number)を求める方法について解説します。カタラン数とは、以下の漸化式で定義される自然数の数列です。$$c_{0} = 1\;and\; c_{n+1} = \displaystyle\sum\limits_{i=0}^nc_{i} c_{n-i}\; for n\geq 0 ;$$n = 0, 1, 2, 3, … に対するカタラン数は、1, 1, 2, 5, 14, 42, 132, 429, …… と続いていきます。カタラン数は、再帰(リカージョン)と動的計画法(DP)のどちらの手法でも求めることができます。それでは、それぞれの実装方法