14 动态规划
-
要点
- 递归 + 记忆化 --> 递推
- 状态的定义: opt[n], dp[n], fib[n]
- 状态转移方程:opt[n] = best_of(opt[n-1], opt[n-2], … )
- 最优子结构
-
动态规划与回溯与贪心算法对比
- 回溯(递归) -- 存在重复计算
- 贪心算法 -- 永远局部最优
- 动态规划 -- 记录局部最优子结构 / 多种记录值
-
leetcode 算法题
class Solution: def climbStairs(self, n: int) -> int: y = x = 1 for _ in range(1, n): y, x = x + y, y return y |
class Solution: def minimumTotal(self, triangle: List[List[int]]) -> int: mini = triangle[-1] length = len(triangle[-1]) for i in range(length-2, -1, -1): for j in range(i+1): mini[j] = triangle[i][j] + min(mini[j], mini[j+1]) return mini[0] |
# 动态规划 class Solution: def maxProduct(self, nums): length = len(nums) if length == 1: return nums[0] res = nums[0] dp = [nums[0] for _ in range(2)] for i in range(1, length): dp = [j * nums[i] for j in dp] dp = [max(dp[0], dp[1], nums[i]), min(dp[0], dp[1], nums[i])] res = max(res, dp[0]) return res
# 递归 class Solution: def maxProduct(self, nums): def recursion(i): if i == 0: return nums[i], nums[i], nums[i] maxi, mini, res = recursion(i-1) maxi, mini = maxi * nums[i], mini * nums[i] return max(maxi, mini, nums[i]), min(maxi, mini, nums[i]), max(maxi, mini, res, nums[i])
return recursion(len(nums) - 1)[2] |
-
股票买卖问题
import sys class Solution: def maxProfit(self, prices: List[int]) -> int: length = len(prices) if length == 1: return 0 res = 0 minprice = sys.maxsize for i in range(length): if prices[i] < minprice: minprice = prices[i] profit = prices[i] - minprice if profit > res: res = profit return res |
# Greedy class Solution: def maxProfit(self, prices: List[int]) -> int: if len(prices) < 2: return 0 profit = 0 for index in range(1, len(prices)): day_profit = prices[index] - prices[index-1] if day_profit > 0: profit += day_profit return profit |
# Greedy class Solution: def maxProfit(self, prices: List[int]) -> int: if len(prices) < 2: return 0 profit = 0 for index in range(1, len(prices)): day_profit = prices[index] - prices[index-1] if day_profit > 0: profit += day_profit return profit |
from sys import maxsize
class Solution: def maxProfit(self, k: int, prices: List[int]) -> int: length = len(prices) if length < 2 or k < 1: return 0 res = 0 if k >= length / 2: for i in range(length - 1): res += max(prices[i + 1] - prices[i], 0) return res
profit = [[[-maxsize for _ in range(2)] for _ in range(k + 1)] for _ in range(2)] profit[0][0] = [0, -prices[0]] pre_index, cur_index = 0, 1 res = 0 for i in range(1, length): profit[cur_index][0][0] = 0 profit[cur_index][0][1] = max(profit[pre_index][0][1], -prices[i])
for count in range(1, min(k + 1, i // 2 + 2)):
profit[cur_index][count][0] = max(profit[pre_index][count][0], profit[pre_index][count - 1][1] + prices[i]) profit[cur_index][count][1] = max(profit[pre_index][count][1], profit[pre_index][count][0] - prices[i]) res = max(res, profit[cur_index][count][0])
cur_index, pre_index = (cur_index + 1) % 2, (pre_index + 1) % 2
return res |
from sys import maxsize class Solution: def maxProfit(self, prices): length = len(prices) if length < 2: return 0 hold, nohold_cold, nohold_nocold = -prices[0], -maxsize, 0 res = 0 for i in range(1, length): hold = max(nohold_nocold - prices[i], hold) nohold_nocold = max(nohold_cold, nohold_nocold) nohold_cold = hold + prices[i] res = max(res, nohold_cold, nohold_nocold) return res |
class Solution: def maxProfit(self, prices: List[int], fee: int) -> int: length = len(prices) if length < 2: return 0 hold, no_hold = -prices[0], 0 res = 0 for i in range(1, length): hold = max(hold, no_hold - prices[i]) no_hold = max(no_hold, hold + prices[i] - fee) res = max(res, no_hold) return res |
# 动态规划 class Solution1: def lengthOfLIS(self, nums: List[int]) -> int: if not nums: return 0 length = len(nums) if length < 2: return 1 res = [1] * length for i in range(1, length): for j in range(i): if nums[j] < nums[i]: res[i] = max(res[i], res[j] + 1)
return max(res)
# 二分查找 class Solution: def lengthOfLIS(self, nums): if not nums: return 0 if len(nums) < 2: return 1 res = [nums[0]] for num in nums[1:]: if num > res[-1]: res.append(num) else: index = self.binary_search(res, num) res[index] = num return len(res)
@staticmethod def binary_search(nums, num): left = 0 right = len(nums) - 1 middle = 0 while left < right: middle = (left + right) // 2 if nums[middle] == num: return middle elif nums[middle] < num: left = middle + 1 else: right = middle
return right# 确保所替换的值一定不小于 num
|
class Solution: def coinChange(self, coins: List[int], amount: int) -> int: res = [amount + 1] * (amount + 1) res[0] = 0 for i in range(1, amount+1): for j in coins: if i - j >= 0: res[i] = min(res[i], res[i - j] + 1) return res[-1] if res[-1] < amount + 1 else -1 |
class Solution: def minDistance(self, word1: str, word2: str) -> int: m, n = len(word1) + 1, len(word2) + 1 dp = [[0 for _ in range(n)] for _ in range(m)] for i in range(m): dp[i][0] = i for j in range(n): dp[0][j] = j for i in range(1, m): for j in range(1, n): dp[i][j] = min(dp[i-1][j-1] + (0 if word1[i-1] == word2[j-1] else 1), dp[i][j-1] + 1, dp[i-1][j] + 1) return dp[-1][-1] |