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

Pythonで解く最小経路合計(Minimum Path Sum)―動的計画法による実装

問題の概要

m × n の行列に非負整数が格納されているとき、左上の角から右下の角へ至る経路のうち、経路上の数値の合計が最小になるものを見つけます。ただし、移動できる方向はどの時点でも「下」または「右」のいずれかに限定されます。

たとえば、次のような行列が与えられたとします。

131
151
421

この場合の出力は 7 となり、最適な経路は 1 → 3 → 1 → 1 → 1 です。この経路を選ぶことで合計が最小になります。

アルゴリズムの手順

この問題は動的計画法(DP)を使うと効率的に解けます。ここでは、入力の行列自体を書き換えながら累積合計を記録していくインプレース方式を採用します。

  1. 行数と列数を取得:row := 行数 − 1、column := 列数 − 1 とします。
  2. 最終行を処理:j を column − 1 から 0 まで減らしながら、grid[row][j] += grid[row][j+1] を実行します。これで最終行の各セルには「そこから右端まで進んだ場合の合計」が格納されます。
  3. 最終列を処理:i を row − 1 から 0 まで減らしながら、grid[i][column] += grid[i+1][column] を実行します。これで最終列の各セルには「そこから下端まで進んだ場合の合計」が格納されます。
  4. 残りのセルを処理:i と j をそれぞれ右下から左上へ向かって減らしながら、grid[i][j] += min(grid[i][j+1], grid[i+1][j]) を実行します。「右に進む場合」と「下に進む場合」のうち、より小さい累積合計の方を選んで加算します。
  5. 結果を返す:grid[0][0] には左上から右下までの最小経路合計が格納されているため、その値を返します。

Pythonでの実装例

class Solution(object):
    def minPathSum(self, grid):
        row = len(grid) - 1
        column = len(grid[0]) - 1
        i = row - 1
        j = column - 1
        # 最終行の処理
        while j >= 0:
            grid[row][j] += grid[row][j + 1]
            j -= 1
        # 最終列の処理
        while i >= 0:
            grid[i][column] += grid[i + 1][column]
            i -= 1
        # 残りのセルの処理
        j = column - 1
        i = row - 1
        while i >= 0:
            while j >= 0:
                grid[i][j] += min(grid[i][j + 1], grid[i + 1][j])
                j -= 1
            j = column - 1
            i -= 1
        return grid[0][0]

ob1 = Solution()
print(ob1.minPathSum([[1, 3, 1], [1, 5, 1], [4, 2, 1]]))

入力

[[1,3,1],[1,5,1],[4,2,1]]

出力

7

計算量について

時間計算量は O(m × n) です。また、入力行列を直接書き換えるため、追加で必要な空間計算量は O(1) となります。元の行列を保持したい場合は、同じサイズのDPテーブルを別途用意して同様の計算を行えば対応できます。

  1. Pythonで二分木のパス合計(Path Sum)を判定する方法

    パス合計問題とは二分木と目標の合計値が与えられたとき、根から葉までの経路をたどった際のノード値の合計が、与えられた値と一致するような経路が存在するかどうかを判定します。例として、木が [0, -3, 9, -10, null, 5] という構成で、合計値が 14 の場合を考えてみましょう。このとき、0 → 9 → 5 という経路が存在し、その合計はちょうど 14 になるため、答えは True となります。解法のアプローチこの問題は再帰を使うことで簡潔に解くことができます。手順は以下の通りです。根ノードが null(空)の場合、False を返します。左右の子ノードが両方とも空(つまり葉ノード)

  2. Pythonで数の因子の最小合計を求めるプログラム|素因数分解の考え方

    本記事では、与えられた整数について、積が元の数と等しくなる因子の組み合わせの中から合計が最小となる値を求める方法を、Pythonのコード例とともに解説します。 問題定義 入力として1つの整数が与えられます。この数を複数の因子の積として表したとき、因子の合計が最小になるケースを求めてください。 すべての因子の組み合わせを網羅的に調べて合計を比較する方法もありますが、実はもっとシンプルで効率的なアプローチが存在します。 考え方:素因数の合計が最小になる 鍵となるのは次の性質です。積が一定の値になるとき、因子の合計が最小になるのは、すべての因子を素数まで分解した場合(素因数分解した場合)です。