509斐波那契
class Solution:
def fib(self, n: int) -> int:
if n == 0:
return 0
dp = [0] * (n + 1)
dp[0] = 0
dp[1] = 1
for i in range(2,n+1):
dp[i] = dp[i-1]+dp[i-2]
return dp[n]
70 爬楼梯,和斐波那契原理一样
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
if n == 2:
return 2
dp = [0]*(n+1)
dp[1] = 1
dp[2] = 2
for i in range(3,n+1):
dp[i] = dp[i-1]+dp[i-2]
return dp[n]
746. 使用最小花费爬楼梯
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
n = len(cost)
dp = [0] * (n+1)
#dp[0] = 0
#dp[1] = 0 前两步不用费用
for i in range(2,n+1):
dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])
return dp[n]
63. 不同路径
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
m = len(obstacleGrid)
n = len(obstacleGrid[0])
dp = [[0 for i in range(n)] for j in range(m)]
if obstacleGrid[0][0] == 0:
dp[0][0] = 1
else:
dp[0][0] = 0
if dp[0][0] == 0: #如果第一个格子有障碍就不走了
return 0
#接下来初始化左边和上边
for i in range(1,m):
if obstacleGrid[i][0] == 1:
break
dp[i][0] = 1
for j in range(1,n):
if obstacleGrid[0][j] == 1:
break
dp[0][j] = 1
for i in range(1,m):
for j in range(1,n):
if obstacleGrid[i][j] != 1: #等于1就是有障碍,保持0不变
dp[i][j] = dp[i-1][j]+dp[i][j-1]
return dp[-1][-1]
343. 整数拆分
class Solution:
def integerBreak(self, n: int) -> int:
dp = [0 for i in range(n+1)]
dp[1],dp[2] = 1,1
for i in range(3,n+1):
for j in range(1,i):
dp[i] = max(dp[i],max(j*(i-j),dp[i-j]*j))
return dp[n]
优化:只需要遍历一半,不用设置dp[i]
class Solution:
def integerBreak(self, n: int) -> int:
dp = [0] * (n + 1)
dp[2] = 1
for i in range(3, n + 1):
# 假设对正整数 i 拆分出的第一个正整数是 j(1 <= j < i),则有以下两种方案:
# 1) 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j * (i-j)
# 2) 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j * dp[i-j]
for j in range(1, i / 2 + 1):
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
return dp[n]
01背包原理
01背包
bag_size = 4
weight = [1, 3, 4]
value = [15, 20, 30]
def bag01(bag_size,weight,value):
rows = len(weight)
cols = bag_size+1
dp = [[0 for i in range(cols)] for j in range(rows)]
#初始化用于先遍历物品的数组
for i in range(rows):
dp[i][0] = 0
first_item_weight = weight[0]
first_item_value = value[0]
for j in range(cols):
if first_item_weight<=j:
dp[0][j] = first_item_value
#先遍历物品,再遍历背包
for i in range(1,rows):
cur_weight = weight[i]
cur_value = value[i]
for j in range(1,cols):
if cur_weight>j:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-cur_weight]+cur_value)
print(dp)
bag01(bag_size,weight,value)
#滚动数组
def bag01_1(bag_size,weight,value):
dp = [0 for _ in range(bag_size+1)]
dp[0] = 0
for i in range(len(weight)):
for j in range(bag_size, weight[i] - 1,-1):
dp[j] = max(dp[j],dp[j-weight[i]]+value[i])
print(dp)
01背包实战
416. 分割等和子集
class Solution:
def canPartition(self, nums: List[int]) -> bool:
target = sum(nums)
if target % 2 != 0:
return False
target = target // 2
dp = [0 for _ in range(target+1)]
#dp[0] = 0
#nums = nums.sort()
for i in range(len(nums)):
for j in range(target,nums[i]-1,-1):
dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
return dp[target] == target
1049. 最后一块石头的重量 II :和上一题有异曲同工之处
class Solution:
def lastStoneWeightII(self, stones: List[int]) -> int:
target = sum(stones) // 2
dp = [0 for _ in range(target+1)]
for i in range(len(stones)):
for j in range(target,stones[i]-1,-1):
dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
return sum(stones)-dp[target]-dp[target]
494. 目标和:组合问题
1 dp[4] -- dp[5]
2 dp[3] -- dp[5]
dp[j] += dp[j - nums[i]]
dp[5] = dp[4]+dp[3]+dp[3]+dp[2].....
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
if ((sum(nums)+target) / 2) % 1 != 0:
return 0
if sum(nums) < abs(target):
return 0
left = (sum(nums)+target) // 2
dp = [0 for _ in range(left+1)]
dp[0] = 1
for i in range(len(nums)):
for j in range(left,nums[i]-1,-1):
dp[j] += dp[j-nums[i]]
return dp[left]
474. 一和零
class Solution:
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
#m - 0
#n - 1
dp = [[0] * (n + 1) for _ in range(m + 1)] # 默认初始化0
for str in strs:
ones = str.count('1')
zeros = str.count('0')
for i in range(m,zeros-1,-1):
for j in range(n,ones-1,-1):
dp[i][j] = max(dp[i-zeros][j-ones]+1,dp[i][j])
return dp[m][n]
#背包的容量有两个维度,都是倒着遍历,str相当于01背包的物品
#注意01背包遍历重量的范围是到第i个物品的重量位置-- zeros-1
完全背包
# 先遍历物品,再遍历背包
def test_complete_pack1():
weight = [1, 3, 4]
value = [15, 20, 30]
bag_weight = 4
dp = [0]*(bag_weight + 1)
for i in range(len(weight)):
for j in range(weight[i], bag_weight + 1):
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(dp[bag_weight])
# 先遍历背包,再遍历物品
def test_complete_pack2():
weight = [1, 3, 4]
value = [15, 20, 30]
bag_weight = 4
dp = [0]*(bag_weight + 1)
for j in range(bag_weight + 1):
for i in range(len(weight)):
if j >= weight[i]: dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(dp[bag_weight])
if __name__ == '__main__':
test_complete_pack1()
test_complete_pack2()
518. 零钱兑换 II
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0 for _ in range(amount+1)]
dp[0] = 1 #一定要初始化1
for i in range(len(coins)):
#先遍历物品
for j in range(coins[i],amount+1):
dp[j] += dp[j-coins[i]] #判断组合数时就这么遍历
return dp[amount]
#如果遍历顺序反过来求的是排列个数
377. 组合总和 Ⅳ
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
dp = [0 for _ in range(target+1)]
dp[0] = 1
for j in range(1,target+1):
for i in range(len(nums)):
if j >= nums[i]: #如果目标数大于容量的话还的是0
dp[j] += dp[j-nums[i]]
return dp[target]
70 爬楼梯进阶版
改为:一步一个台阶,两个台阶,三个台阶,.......,直到 m个台阶。问有多少种不同的方法可以爬到楼顶呢?
class Solution:
def climbStairs(self, n: int) -> int:
dp = [0]*(n + 1)
dp[0] = 1
m = 2
# 遍历背包
for j in range(n + 1):
# 遍历物品
for step in range(1, m + 1):
if j >= step:
dp[j] += dp[j - step]
return dp[n]
美团动态规划两题
n = 7
candies = [3,1,2,7,10,2,4]
#动态规划
#1.dp i ,前i个糖果取得的最大值
#i为1时只能选第一个
#i为2时选前两个更大的那个
#i为3时选选前三个中更大的 dp[3] = max(dp[2],candies[1])
#递归公式 dp[i] = max(max(dp[i-2],dp[i-1]),dp[i-3]+candies[i-1])
def largest_taste(n,candies):
dp = [0] * (len(candies)+1)
dp[1] = candies[0]
dp[2] = max(candies[1],candies[0])
for i in range(3,n+1):
dp[i] = max(max(dp[i-1],dp[i-2]),dp[i-3]+candies[i-1])
return dp,dp[n]
print(largest_taste(n,candies))
n = 7
k = 1
nums= [1,2,3,4,5,6,7]
#dp[i][j][0/1] 在第i天打破原则j次,当前这一天是否吃糖
dp = [[[0 for _ in range(2)] for _ in range(k+1)] for _ in range(n)]
dp[0][0][1] = nums[0] #第一天吃糖
for i in range(1,n):
dp[i][0][0] = max(dp[i][0][0],dp[i-1][0][1])
dp[i][0][1] = dp[i-1][0][0] + nums[i]
for j in range(1,k+1):
dp[i][j][0] = max(dp[i-1][j][0],dp[i-1][j][1])
dp[i][j][1] = max(dp[i-1][j-1][1],dp[i-1][j][0])+nums[i]
print(max(dp[n-1][k][0],dp[n-1][k][1]))