动态规划是一种解决多阶段决策过程最优化问题的数学方法。通常需要保存决策路径的问题用回溯法,而只是求最优解的时候选择动态规划。
链接: https://leetcode.cn/problems/Gu0c2T/
一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响小偷偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组nums
,请计算不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:nums = [1,2,3,1] 输出:4 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
class Solution:
def rob(self, nums: List[int]) -> int:
len_nums = len(nums)
# 定义边界条件
if len_nums == 0:
return 0
if len_nums == 1:
return nums[0]
dp = []
dp.append(nums[0])
dp.append(max(nums[1], nums[0]))
for idx in range(2, len_nums, 1):
dp[idx % 2] = max(dp[(idx - 1) % 2], dp[(idx - 2) % 2] + nums[idx]) # 只需要用两个值来缓存中间结果
return dp[(len_nums - 1) % 2]
链接:https://leetcode.cn/problems/PzWKhm/
环形房屋,即第一个房屋和最后一个房屋也不能同时被打劫。该问题可以看做是求以下两个子问题的最大值:
def helper(nums, start, end):
dp = []
dp.append(nums[start])
if start < end:
dp.append(max(nums[start], nums[start + 1]))
for i in range(start + 2, end + 1, 1):
j = i - start
dp[j % 2] = max(dp[(j - 1) % 2], dp[(j - 2) % 2] + nums[i])
return dp[(end - start) % 2]
class Solution:
def rob(self, nums: List[int]) -> int:
len_nums = len(nums)
if len_nums == 0:
return 0
if len_nums == 1:
return nums[0]
return max(helper(nums, 0, len(nums) - 2), helper(nums, 1, len(nums) - 1))
链接:https://leetcode.cn/problems/JEj789/description/
假如有一排房子,共 n 个,每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。 当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x 3 的正整数矩阵 costs 来表示的。 例如,costs[0][0] 表示第 0 号房子粉刷成红色的成本花费;costs[1][2] 表示第 1 号房子粉刷成绿色的花费,以此类推。 请计算出粉刷完所有房子最少的花费成本。 示例 1: 输入: costs = [[17,2,17],[16,16,5],[14,3,19]] 输出: 10 解释: 将 0 号房子粉刷成蓝色,1 号房子粉刷成绿色,2 号房子粉刷成蓝色。 最少花费: 2 + 5 + 3 = 10。
示例 2: 输入: costs = [[7,6,2]] 输出: 2
dp[0][i] = min(dp[1][i - 1], dp[2][i - 1]) + cost[i][0]
dp[1][i] = min(dp[0][i - 1], dp[2][i - 1]) + cost[i][1]
dp[2][i] = min(dp[1][i - 1], dp[0][i - 1]) + cost[i][2]
result = min(dp[0][last], dp[1][last], dp[2][last])
dp[0][0] = cost[0][0]
dp[1][0] = cost[0][1]
dp[2][0] = cost[0][2]
def minCost(self, costs: List[List[int]]) -> int:
len_costs = len(costs)
last = len_costs - 1
if len_costs == 0:
return 0
dp = [[None for _ in range(len_costs)] for _ in range(3)]
for i in range(3):
dp[i][0] = costs[0][i]
for i in range(1, len_costs):
dp[0][i] = min(dp[1][i - 1], dp[2][i - 1]) + costs[i][0]
dp[1][i] = min(dp[0][i - 1], dp[2][i - 1]) + costs[i][1]
dp[2][i] = min(dp[1][i - 1], dp[0][i - 1]) + costs[i][2]
return min(dp[0][last], dp[1][last], dp[2][last])
链接: https://leetcode.cn/problems/cyJERH/description/
如果一个由 ‘0’ 和 ‘1’ 组成的字符串,是以一些 ‘0’(可能没有 ‘0’)后面跟着一些 ‘1’(也可能没有 ‘1’)的形式组成的,那么该字符串是 单调递增 的。 我们给出一个由字符 ‘0’ 和 ‘1’ 组成的字符串 s,我们可以将任何 ‘0’ 翻转为 ‘1’ 或者将 ‘1’ 翻转为 ‘0’。 返回使 s 单调递增 的最小翻转次数。
示例 1:
输入:s = “00110” 输出:1 解释:我们翻转最后一位得到 00111.
示例 2:
输入:s = “010110” 输出:2 解释:我们翻转得到 011111,或者是 000111。
示例 3:
输入:s = “00011000” 输出:2 解释:我们翻转得到 00000000。
dp_f[i] = dp_f[i - 1] if s[i] == "0" else dp_f[i - 1] + 1
dp_g[i] = min(dp_f[i - 1], dp_g[i - 1]) if s[i] == "1" else min(dp_f[i - 1], dp_g[i - 1]) + 1
寻找初始值
dp_f[0] = 0 if s[0] == "0" else 1
dp_g[0] = 0 if s[0] == "1" else 1
class Solution:
def minFlipsMonoIncr(self, s: str) -> int:
len_s = len(s)
if len_s <= 1:
return 0
f_cache = 0 if s[0] == "0" else 1
g_cache = 0 if s[0] == "1" else 1
dp_f = f_cache
dp_g = g_cache
for i in range(1, len_s):
dp_f = f_cache if s[i] == "0" else f_cache + 1
dp_g = min(g_cache, f_cache) if s[i] == "1" else min(g_cache, f_cache) + 1
f_cache, g_cache = dp_f, dp_g
return min(dp_f, dp_g)
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有