面試題14- i. 剪繩子/343. 整數拆分
面試題42. 連續子陣列的最大和/53. 最大子序和
面試題47. 禮物的最大價值
給定乙個正整數 n,將其拆分為至少兩個正整數的和,並使這些整數的乘積最大化。 返回你可以獲得的最大乘積。
示例 1:
輸入: 2
輸出: 1
解釋: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
輸入: 10
輸出: 36
解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
假設n的最大值為f(n),可以將n拆分成i和n-i,問題變成 i乘以f(n-i),這樣就變成了f(k),k
和第一步一樣,使用dp表示其值,但是要注意 i * (n - i) 本省也可能成為最大值;另外因為是遍歷迴圈,要考慮計算過的dp[i],因此得到如下表示式:
dp[i] = max(dp[i], max(i * dp(n - i),i * (n - i)))
初始值:每個dp都設定為1
而這裡的 n 是什麼呢?我們說了dp是自底向下的思考方式。因此這裡的 n 實際上是 1,2,3,4... n。
自然地,我們用一層迴圈來生成上面一系列的 n 值。接著我們還要生成一系列的 i 值,注意到 n - i 是要大於 0 的,因此 i 只需要迴圈到 n - 1 即可。
因為要迴圈使用,所以無法進行空間優化
classsolution:
defintegerbreak(self, n: int) -> int:
dp=[1]*(n+1)
fori inrange(3,n+1):
forj inrange(1,i):
dp[i] = max(j*dp[i-j],j*(i-j),dp[i])
returndp[-1]
輸入乙個整型陣列,陣列裡有正數也有負數。陣列中的乙個或連續多個整數組成乙個子陣列。求所有子陣列的和的最大值。
要求時間複雜度為o(n)。
示例1:
輸入: nums = [-2,1,-3,4,-1,2,1,-5,4]
輸出: 6
解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。
問題比較簡單,一維陣列的問題。
假設n的最大值為f(n),可以將n拆分成i和n-i,問題變成 i加上f(n-i)或直接是f(n-i),這樣就變成了f(k),k
很明顯,使用自底向上的方式進行。具體**見2.3的**一
從**也很明顯看到,只用了
dp[i-1]
這個前置項,另外是最後輸出的
max(dp)
也需要保留,其它是暫存也沒有用到,所以可將其優化,將
dp[i-1]
用max_temp,最後的輸出使用res。具體可見**二。
**一:
classsolution:
defmaxsubarray(self, nums: list[int]) -> int:
n = len(nums)
ifn == 0:return0
else:
dp = [nums[0]] *(n)
fori inrange(1,n):
#注意這裡不是n+1
dp[i] = max(dp[i-1]+nums[i],nums[i])
returnmax(dp)
**二:
classsolution:
defmaxsubarray(self, nums: list[int]) -> int:
n = len(nums)
ifn == 0:return0
else:
max_temp = nums[0]
res = max_temp
fori inrange(1,n):
max_temp = max(max_temp + nums[i],nums[i])
res = max(res,max_temp)
returnres
在乙個 m*n 的棋盤的每一格都放有乙個禮物,每個禮物都有一定的價值(價值大於 0)。你可以從棋盤的左上角開始拿格仔裡的禮物,並每次向右或者向下移動一格、直到到達棋盤的右下角。給定乙個棋盤及其上面的禮物的價值,請計算你最多能拿到多少價值的禮物?
示例 1:
輸入:
[[1,3,1],
[1,5,1],
[4,2,1]
]輸出: 12
解釋: 路徑 1→3→5→2→1 可以拿到最多價值的禮物
是二維陣列題,難度為中等偏上,和這題【1143. 最長公共子串行】類似
題目說明:從棋盤的左上角開始拿格仔裡的禮物,並每次 向右 或者 向下 移動一格、直到到達棋盤的右下角。
根據題目說明,易得某單元格只可能從上邊單元格或左邊單元格到達。
很明顯,縮小規模的子問題和原文題是等效的。
定義二維矩陣,設動態規劃矩陣 dp,
dp(i,j)
代表從棋盤的左上角開始,到達單元格
(i,j)
時能拿到禮物的最大累計價值。
先行後列,從上到下進行計算即可。具體**見3.3**一。
對角進行替換,換成下圖所示的例子,進一步優化空間:
temp
dp[j-1]
dp[j-1]
只是用上面和左邊的,所以可以重複利用,迴圈推進就可以了。具體見**二。
**一:
classsolution:
defmaxvalue(self, grid: list[list[int]]) -> int:
m = len(grid)
n = len(grid[0])
dp = [[0]*(n+1) for_ inrange(m+1)] #(m+1)(n+1)
的矩陣fori inrange(1,m+1): #
注意要從
1開始,結束為
m+1forj inrange(1,n+1):
dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + grid[i-1][j-1]
returndp[-1][-1]
classsolution:
defmaxvalue(self, grid: list[list[int]]) -> int:
m = len(grid)
n = len(grid[0])
dp = [0]*(n+1) #(n+1)
的陣列fori inrange(1,m+1): #
注意要從
1開始,結束為
m+1forj inrange(1,n+1):
temp = dp[j]
#這個也可省略,因為是迴圈更新,可以代表d[i-1][j]
dp[j] = max(temp,dp[j-1]) + grid[i-1][j-1]
returndp[-1]
動態規劃演算法(DP)
動態規劃演算法採用分治演算法的思想,將原問題分成若干個子問題,然後分別求解各個子問題,最後將子問題的解組合起來得到原問題的解。分治演算法遞迴地求解各個子問題,可能重複求解某些子問題。與分治演算法不同的是,動態規劃演算法不是遞迴地求解各個子問題,它是從簡單問題的解入手,逐步求解,直至求解出原問題。動態...
動態規劃演算法解析
數字三角形 poj1163 在上面的數字三角形中尋找一條從頂部到底邊的路徑,使得路徑上所經過的數字之和最大。路徑上的每一步都只能往左下或 右下走。只需要求出這個最大和即可,不必給出具體路徑。三角形的行數大於1小於等於100,數字為 0 99 輸入格式 5 表示三角形的行數 接下來輸入三角形 3 88...
動態規劃演算法
一 動態規劃演算法原理 將待求解的問題分解成若干個相互聯絡的子問題,先求解子問題,然後從這些子問題的解得到原問題的解 對於重複出現的子問題,只在第一次遇到的時候對它進行求解,並把答案儲存起來。了不去求解相同的子問題,引入乙個陣列,把所有子問題的解存於該陣列中,這就是動態規劃所採用的基本方法。動態規劃...