給定一個包含非負整數的 m x n 網格,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和爲最小。數組
說明:每次只能向下或者向右移動一步。app
示例:佈局
輸入: [ [1,3,1], [1,5,1], [4,2,1] ] 輸出: 7 解釋: 由於路徑 1→3→1→1→1 的總和最小。
新建一個矩陣dp(大小也是M*N),該矩陣是從上往下,從左往右記錄每一步的結果的,當前的結果能夠根據該矩陣上面和左邊最小的值來得到,即:優化
dp[i][j] = min(dp[i][j-1],dp[i-1][j]) + grid[i][j]
如:spa
grid = 3d [ [1,3,1], |
dp = blog [[1,4,5], |
因此結果爲dp[-1][-1] = 7ip
def minPathSum(self, grid): """ :type grid: List[List[int]] :rtype: int """ #使用二維數組 if not grid or not grid[0]: return 0 if len(grid) <= 1: return sum(grid[0]) dp = [[0]*len(grid[0]) for i in range(len(grid))] dp[0][0] = grid[0][0] for i in range(1,len(grid)): dp[i][0] = grid[i][0] + dp[i-1][0] for j in range(1,len(grid[0])): dp[0][j] = grid[0][j] + dp[0][j-1] for i in range(1,len(grid)): for j in range(1,len(grid[0])): dp[i][j] = min(dp[i][j-1],dp[i-1][j]) + grid[i][j] return dp[-1][-1]
新建一個列表dp(大小爲min(M,N)),循環行數次更新記錄每一行的路徑值。
如:
grid =
[ [1,3,1],
[1,5,1],
[4,2,1]]
第一次更新:dp = [1,4,5]
第二次更新:dp = [2,7,6],好比:本來dp = [1,4,5],而後 先將 dp[0] 更新爲2,而後dp[1] : 【min ( dp[0] 和dp [1] ) 與grid [1][1]相加之和】來更新 dp [1]
第三次更新:dp = [6,8,7]
更新是根據:
dp[j] = min(dp[j-1],dp[j]) + grid[i][j]
#使用一維數組 if not grid or not grid[0]: return 0 if len(grid) <= 1: return sum(grid[0]) if len(grid[0]) <= 1: return sum([val[0] for val in grid]) n = min(len(grid),len(grid[0])) m = len(grid) if n == len(grid[0]) else len(grid[0]) dp = [0] * n dp[0] = grid[0][0] if n == len(grid): grid = list(zip(*grid)) for i in range(1,n): dp[i] = grid[0][i] + dp[i-1] for i in range(1,m): for j in range(n): dp[j] = min(dp[j-1],dp[j]) + grid[i][j] if j>=1 else dp[j] + grid[i][j] return dp[-1]
例如,考慮到以下佈局的地下城,若是騎士遵循最佳路徑 右 -> 右 -> 下 -> 下
,則騎士的初始健康點數至少爲 7。
該題與最短路徑相反。該題從最右下方開始,求起點。由於題目求的是初始血量,而最短路徑求的是終點值,二者相反。
dp[i][j]:若是騎士要走上位置(i,j),而且從該位置選一條最優的路徑,最後走到右下角,騎士起碼應具有的血量。最終結果爲dp[0][0]。
狀態方程:
dp[i][n-1] = max(dp[i+1][n-1] - dungeon[i][n-1],1)
dp[m-1][j] = max(dp[m-1][j+1] - dungeon[m-1][j],1)
def minHP1(mat): if mat == None or mat[0] == None or len(mat) == 0 or len(mat[0]) == 0: return 1 row = len(mat) col = len(mat[0]) dp = [[0 for i in range(col)] for j in range(row)]
#初始化 dp[row-1][col-1] = max(-mat[row-1][col-1]+1, 1) for i in range(row-2, -1, -1): dp[i][col-1] = max(dp[i+1][col-1] - mat[i][col-1], 1) for j in range(col-2, -1, -1): dp[row-1][j] = max(dp[row-1][j+1] - mat[row-1][j], 1)
#更新dp[i][j] for i in range(row-2, -1, -1): for j in range(col-2, -1, -1): right = max(dp[i][j+1] - mat[i][j], 1) down = max(dp[i+1][j] - mat[i][j], 1) dp[i][j] = min(right, down) return dp[0][0] mat = [[-2,-3,3],[-5,-10,1],[10,30,-5]] minHP1(mat)
給定一個三角形,找出自頂向下的最小路徑和。每一步只能移動到下一行中相鄰的結點上。
例如,給定三角形:
[ [2], [3,4], [6,5,7], [4,1,8,3] ]
自頂向下的最小路徑和爲 11
(即,2 + 3 + 5 + 1 = 11)。
dp【i】【j】:表示第i行第j列時最短路徑。
子問題:鄰近的兩個:dp[i-1][j-1]、dp[i-1][j]
狀態方程:dp[i][j] = min(dp[i-1][j-1],dp[i-1][j]) + triangle[i][j]
def minimumTotal(self, triangle): """ :type triangle: List[List[int]] :rtype: int """ m = len(triangle) n = len(triangle[0]) if not triangle or m == 0 or n == 0: return 0 dp = [[triangle[0][0]]] for i in range(1,m): dp.append([0] * len(triangle[i])) # print(dp) for i in range(1,m): dp[i][0] = dp[i-1][0] + triangle[i][0] dp[i][-1] = dp[i-1][-1] + triangle[i][-1] for j in range(1,len(dp[i])-1): dp[i][j] = min(dp[i-1][j-1],dp[i-1][j]) + triangle[i][j] return min(dp[-1])
狀態方程:dp[j] = min(dp[j],dp[j+1]) + triangle[i][j]
#一維數組 dp = triangle[-1] for i in range(m-2,-1,-1): for j in range(len(triangle[i])): dp[j] = min(dp[j],dp[j+1]) + triangle[i][j] return dp[0]
給定一個方形整數數組 A
,咱們想要獲得經過 A
的降低路徑的最小和。
降低路徑能夠從第一行中的任何元素開始,並從每一行中選擇一個元素。在下一行選擇的元素和當前行所選元素最多相隔一列。
示例:
輸入:[[1,2,3],[4,5,6],[7,8,9]] 輸出:12 解釋: 可能的降低路徑有:
[1,4,7], [1,4,8], [1,5,7], [1,5,8], [1,5,9]
[2,4,7], [2,4,8], [2,5,7], [2,5,8], [2,5,9], [2,6,8], [2,6,9]
[3,5,7], [3,5,8], [3,5,9], [3,6,8], [3,6,9]
和最小的降低路徑是 [1,4,7]
,因此答案是 12
。
提示:
1 <= A.length == A[0].length <= 100
-100 <= A[i][j] <= 100
def minFallingPathSum(self, A): """ :type A: List[List[int]] :rtype: int """ if not A or len(A[0]) == 0: return 0 m , n = len(A),len(A[0]) dp = [[0] * n for i in range(m)] dp[0] = A[0] for i in range(1,m): for j in range(n): if j==0: dp[i][j] = min(dp[i-1][j+1],dp[i-1][j]) + A[i][j] elif j == n-1: dp[i][j] = min(dp[i-1][j-1],dp[i-1][j]) + A[i][j] else: dp[i][j] = min(dp[i-1][j-1],dp[i-1][j+1],dp[i-1][j]) + A[i][j] return min(dp[-1])
一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記爲「Start」 )。
機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記爲「Finish」)。
如今考慮網格中有障礙物。那麼從左上角到右下角將會有多少條不一樣的路徑?
網格中的障礙物和空位置分別用 1
和 0
來表示。
說明:m 和 n 的值均不超過 100。
示例 1:
輸入: [ [0,0,0], [0,1,0], [0,0,0] ] 輸出: 2 解釋: 3x3 網格的正中間有一個障礙物。 從左上角到右下角一共有 條不一樣的路徑: 1. 向右 -> 向右 -> 向下 -> 向下 2. 向下 -> 向下 -> 向右 -> 向右 2
def uniquePathsWithObstacles(self, obstacleGrid): """ :type obstacleGrid: List[List[int]] :rtype: int """ if not obstacleGrid or len(obstacleGrid[0]) == 0 or obstacleGrid[0][0] == 1: return 0 m , n = len(obstacleGrid) , len(obstacleGrid[0]) dp = [[0] * n for i in range(m)] dp[0][0] = 1 if obstacleGrid[0][0] != 1 else 0 for i in range(1,m): if obstacleGrid[i][0] == 0 and dp[i-1][0] == 1: dp[i][0] = 1 for j in range(1,n): if obstacleGrid[0][j] == 0 and dp[0][j-1] == 1: dp[0][j] = 1 for i in range(1,m): for j in range(1,n): if obstacleGrid[i][j] == 0: dp[i][j] = dp[i-1][j] + dp[i][j-1] return dp[-1][-1]
給定一個 m × n 的網格和一個球。球的起始座標爲 (i,j) ,你能夠將球移到相鄰的單元格內,或者往上、下、左、右四個方向上移動使球穿過網格邊界。可是,你最多能夠移動 N 次。找出能夠將球移出邊界的路徑數量。答案可能很是大,返回 結果 mod 109 + 7 的值。
示例 1:
輸入: m = 2, n = 2, N = 2, i = 0, j = 0 輸出: 6 解釋:
示例 2:
輸入: m = 1, n = 3, N = 3, i = 0, j = 1 輸出: 12 解釋:
說明:
對於一個起始點爲i,j,N步能夠走出的點的路徑個數,等於該點周圍的4個點,N-1步能夠走出的路徑個數之和
dp[k][i][j]表示起點在[i][j], 第k步能夠走出路徑個數之和。
def findPaths(self, m, n, N, i, j): """ :type m: int :type n: int :type N: int :type i: int :type j: int :rtype: int """ dp = [[[0] * n for y in range(m)] for k in range(N+1)] for k in range(1,N+1): for x in range(m): for y in range(n): n1 = dp[k-1][x-1][y] if x >= 1 else 1 n2 = dp[k-1][x][y-1] if y >= 1 else 1 n3 = dp[k-1][x+1][y] if x < m-1 else 1 n4 = dp[k-1][x][y+1] if y < n-1 else 1 dp[k][x][y] = (n1+n2+n3+n4)%(10**9 + 7) return dp[N][i][j]