10.3.1 (python) 動態規劃數組類LeetCode題目 —— Minimum Path Sum & Triangle & Maximum Product Subarray

這一節的幾篇,都是解析動態規劃數組類題目,相對於後面的字符串類問題來說,還是比較容易的。

首先來看比較幾個簡單的DP題目,鞏固一下前面所學套路。

64. Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

題目解析:

貌似63題的通過率還低些,不過就不解析了,DP框架不變,由於障礙物的關係略微修改邊界和狀態轉移方程。

路徑和還是經常和大家碰面的問題,比如在二叉樹的時候。

這道題仍然不變算法框架,f(i,j)代表到達i,j點時的最小路徑和,然後我們研究f(i,j)和f(i-1,j),f(i,j-1)之間的關係。對於邊界的定義也略微不同。直接看代碼,此次已優化了空間,這樣寫起來索引也好懂。。

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        dp = [0] * n
        # 第一行邊界
        dp[0] = grid[0][0]
        for i in range(1, n):
            dp[i] = dp[i-1] + grid[0][i]
        for i in range(1, m):
            for j in range(n):
                if j == 0: # 第一列邊界
                    dp[j] += grid[i][j]
                else:
                    # 關係式
                    dp[j] = min(dp[j], dp[j-1]) + grid[i][j]
        return dp[n-1]

 120. Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

題目解析:

還是路徑問題,算法框架和狀態轉移方程其實都和上面的差不多啦,不同的是數組每行的數目不同,需額外注意索引和邊界問題。另外對於dp數組的更新比較麻煩,索性用了兩個dp數組。

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        n = len(triangle)
        if n == 1:
            return triangle[0][0]
        if n ==2:
            return triangle[0][0] + min(triangle[1][0], triangle[1][1])
        
        dp_ = [0] * n
        dp_[0] = triangle[0][0] + triangle[1][0]
        dp_[1] = triangle[0][0] + triangle[1][1]
        for i in range(3, n+1): # i是行數 索引爲i-1
            dp = [0] * n
            for j in range(i):  # 每行 j代表列索引
                if j == 0:
                    dp[j] = dp_[j] + triangle[i-1][0]
                elif j == i-1:
                    dp[j] = dp_[j-1] + triangle[i-1][j]
                else:
                    dp[j] = min(dp_[j], dp_[j-1]) + triangle[i-1][j]
            dp_ = dp
        return min(dp_)

152. Maximum Product Subarray

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

題目解析:

前面有一道Maximum Subarray 最大連續和,圖森破了就不介紹了。這道題是乘積,沒有小數,但是會有0和負數。

1. 出現0的情況下重新往後算,另外0也可能是最大值;

2. 重點考慮負數*負數得到較大的乘積的形式,因此我們要記錄兩個值,一個是連續乘積最大值(正數),一個是連續乘積最小值(負數);當前數字爲是正數或負數,需要用不同的方式更新這兩個記錄。

下面我們看代碼,我們用dp_pos[i]和dp_neg[i]分別表示這兩個值在i處的情況,當然我們可以優化爲O(1)空間的。由於題目思路稍微複雜點,我們先寫成O(n)空間的,理解了思路後再優化。

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        if not nums:
            return 0
        l = len(nums)        
        if l == 1:
            return nums[0]
        
        dp_pos = [0] * l
        dp_neg = [0] * l
        dp_pos[0] = max(nums[0], 0)
        dp_neg[0] = min(nums[0], 0)
        for i in range(1, l):
            num = nums[i]
            if num == 0:
                continue
            elif num > 0:
                # 當前數字爲正
                dp_pos[i] = max(num, dp_pos[i-1] * num)
                dp_neg[i] = min(num, dp_neg[i-1] * num)
            else:
                # 當前數字爲負
                dp_pos[i] = max(num, dp_neg[i-1] * num)
                dp_neg[i] = min(num, dp_pos[i-1] * num)
                
        return max(dp_pos)

這是幾道稍加變形的DP題目,屬於DP中必會的。後面我們會逐漸介紹有難度的題目

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章