LeetCodeの動的計画法2つの異なるパス(62)、異なるパスII(63)、最小パス、および(64)

1.異なるパス(62)

タイトル説明:

【中】
ロボットはmxnグリッドの左上隅にあります(下図では開始点が「開始」と表示されています)。

ロボットは、一度に1ステップ下または右にしか移動できません。ロボットはグリッドの右下隅に到達しようとします(下の画像で「完了」とラベル付けされています)。

合計でいくつの異なるパスがありますか?
例:
ここに画像の説明を挿入します

输入:m = 3, n = 7
输出:28

トピックリンク

思考分析

1.各ステップで1ステップ下または右にしか移動できないため、(i、j)(i、j)に移動する場合は、1ステップ下に移動すると、(i- 1、j)(i-1、j)がやってくる;右に一歩進むと(i、j-1)(i、j-1)からやってくる。

2.次に、動的計画法を使用して、解決のために重複するサブ問題に分解できます。

ステップ1:ステータスを定義する

dp[i][j]:左上隅から位置(i、j)までのパスの総数を示します

ステップ2:状態遷移方程式

dp[i][j] = dp[i-1][j] + dp[i][j-1]
  • dp [i-1] [j]は、上からのパスの数を表します。
  • dp [i] [j-1]は、左からのパスの数を表します。

ステップ3:初期値(境界条件)

  • 最初の行dp [0] [j]または最初の列dp [i] [0]の場合、これらはすべて境界上にあるため、1のみになります。
  • dp [0] [j] == 1; dp [i] [0] == 1

ステップ4:反射出力、戻り値

  • dp行列の右下隅の値、つまり、終点までのさまざまなパスの総数を返します。
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        dp=[[0]*n for _ in range(m)]
        # 初始化
        for i in range(m):
            dp[i][0]=1
        for j in range(n):
            dp[0][j]=1
        # 转移方程,进行填充
        for i in range(1,m):
            for j in range(1,n):
                dp[i][j]=dp[i-1][j]+dp[i][j-1]
        return dp[-1][-1]
  • 時間計算量:O(mn)O(mn)O m n
  • スペースの複雑さ:O(mn)O(mn)O m n

ステップ5:状態の圧縮について考える

  • 毎回dp [i-1] [j]、dp [i] [j-1]しか必要ないので、これら2つの数値を記録するだけで済みます。
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        cur = [1] * n
        for i in range(1, m):
            for j in range(1, n):
                cur[j] += cur[j-1]
        return cur[-1]

  • 時間計算量:O(mn)O(mn)O m n
  • スペースの複雑さ:O(n)O(n)O n

2.異なるパスII(63)

タイトル説明:

【中】
ロボットはmxnグリッドの左上隅にあります(下図では開始点が「開始」と表示されています)。

ロボットは、一度に1ステップ下または右にしか移動できません。ロボットはグリッドの右下隅に到達しようとします(下の画像で「完了」とラベル付けされています)。

ここで、グリッドに障害物があると考えてください。では、左上隅から右下隅まで、いくつの異なるパスがありますか?
ここに画像の説明を挿入します
グリッド内の障害物と空の位置は、それぞれ1と0で表されます。
例1:
ここに画像の説明を挿入します

 输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

トピックリンク

思考分析

3.最小パス合計(64)

タイトル説明:

【中】

非負の整数を含むmxnグリッドがある場合、パス上の数値の合計が最小になるように、左上隅から右下隅へのパスを見つけてください。

注:一度に移動できるのは、1ステップ下または右のみです。

例1
ここに画像の説明を挿入します

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 13111 的总和最小。

促す:

  • m == grid.length
  • n == grid [i] .length
  • 1 <= m、n <= 200
  • 0 <=グリッド[i] [j] <= 100

トピックリンク

思考分析

1.パスの方向は下または右にしかできないため、グリッドの最初の行の各要素は左上隅の要素から右にのみ移動でき、グリッドの最初の列の各要素は開始のみが可能です。左上隅の要素から下に移動して到着すると、この時点でのパスは一意であるため、各要素に対応する最小パスの合計は、対応するパスの数値の合計になります。

2.最初の行と最初の列にない要素の場合、その上の隣接する要素から1ステップ下に移動するか、左側の隣接する要素から1ステップ右に移動し、に対応する最小パスを指定できます。要素は、その上の隣接する要素と同じです。要素とその左側の隣接する要素に対応する最小パスの合計に、現在の要素の最小値を加えたものです。各要素に対応する最小パスは、隣接する要素に対応する最小パスの合計に関連しているため、動的計画法を使用して問題を解決できます。

ステップ1:ステータスを定義する

dp[i][j]:左上隅から位置(i、j)までの最小経路合計を表します。易知dp[0][0]=grid[0][0]

ステップ2:状態遷移方程式

  • i = 0およびj = 0の場合、行列の左上隅の要素は開始点でもあります:dp[0][0]=grid[0][0]
  • i = 0で、j> 0が行列の最初の行である場合:dp[0][j]=dp[0][j-1]+grid[0][j]
  • i> 0で、j = 0が行列の最初の列の場合:dp[i][0]=dp[i-1][0]+grid[i][0]
  • i> 0およびj> 0が行列の非境界要素である場合:dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j]

ステップ3:初期値(境界条件)

  • dpは初期化できます

ステップ4:反射出力、戻り値

  • dp行列の右下隅の値、つまり、最後までの最小パスとを返します。

ステップ5:状態の圧縮について考える

  • dp行列は元の行列と同じ次元であるため、元の行列を現在の位置の最小パス合計に直接変更できます。
class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if i == j == 0: continue
                elif i == 0:  grid[i][j] = grid[i][j - 1] + grid[i][j]
                elif j == 0:  grid[i][j] = grid[i - 1][j] + grid[i][j]
                else: grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]
        return grid[-1][-1]
  • 時間計算量:O(mn)O(mn)O m n :行列全体をトラバースします
  • スペースの複雑さ:O(1)O(1)O 1 :余分なスペースを使用せずに元の行列を直接変更する

おすすめ

転載: blog.csdn.net/weixin_45666566/article/details/113487912