70. 爬楼梯(进阶版)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
n, m = map(int, input().split())
dp = [0] * (n+1)
dp[0] = 1
for j in range(1, n+1):
for i in range(1, m+1):
if j >= i:
dp[j] += dp[j-i]
print(dp[n])
322. 零钱兑换*
给你一个整数数组 coins
,表示不同面额的硬币;以及一个整数 amount
,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1
。
你可以认为每种硬币的数量是无限的。
随想录解法:推导出来了状态转移方程,但是卡在了dp数组的初始化,不能全部初始化为0或者-1,因为这两个数都是有含义的。因为要取最小值,自然初始化成最大值
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
# dp = [-1] * (amount+1)
# dp[0] = 0
# # if num == j: dp[j] = 1
# # dp[j] = min(dp[j], dp[j-num]+1) if dp[j] > 0 else dp[j-num] + 1
# # * 0 1 2 3 4 5 6
# # 1 0 1 2 3 4 5 6
# # 2 0 1 1 2 2 3 3
# for coin in coins:
# for j in range(coin, amount+1):
# if coin == j:
# dp[j] = 1
# elif dp[j] >= 0:
# dp[j] = min(dp[j], dp[j-coin] + 1)
# elif dp[j-coin] >= 0:
# dp[j] = dp[j-coin] + 1
# else:
# dp[j] = -1
# return dp[amount]
dp = [float('inf')] * (amount + 1) # 创建动态规划数组,初始值为正无穷大
dp[0] = 0 # 初始化背包容量为0时的最小硬币数量为0
for coin in coins: # 遍历硬币列表,相当于遍历物品
for i in range(coin, amount + 1): # 遍历背包容量
if dp[i - coin] != float('inf'): # 如果dp[i - coin]不是初始值,则进行状态转移
dp[i] = min(dp[i - coin] + 1, dp[i]) # 更新最小硬币数量
if dp[amount] == float('inf'): # 如果最终背包容量的最小硬币数量仍为正无穷大,表示无解
return -1
return dp[amount] # 返回背包容量为amount时的最小硬币数量
279.完全平方数
给你一个整数 n
,返回 和为 n
的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1
、4
、9
和 16
都是完全平方数,而 3
和 11
不是。
class Solution:
def numSquares(self, n: int) -> int:
# items = []
# for i in range(1, n):
# if i * i < n:
# items.append(i)
dp = [n] * (n+1)
dp[0] = 0
for i in range(1, n + 1):
for j in range(i*i, n+1):
dp[j] = min(dp[j], dp[j-i*i] + 1)
return dp[n]
139.单词拆分
给你一个字符串 s
和一个字符串列表 wordDict
作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s
则返回 true
。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
难点在于给出动态数组的递推公式:
如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )。
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
dp = [False]*(len(s) + 1)
dp[0] = True
# 遍历背包
for j in range(1, len(s) + 1):
# 遍历单词
for word in wordDict:
if j >= len(word):
dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
return dp[len(s)]
多重背包问题*
有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。
每件物品最多有Mi件可用,把Mi件摊开,其实就是一个01背包问题了。
C, N = input().split(" ")
C, N = int(C), int(N)
# value数组需要判断一下非空不然过不了
weights = [int(x) for x in input().split(" ")]
values = [int(x) for x in input().split(" ") if x]
nums = [int(x) for x in input().split(" ")]
dp = [0] * (C + 1)
# 遍历物品
for i in range(N):
# 遍历背包容量
for j in range(C, weights[i] - 1, -1):
for k in range(1, nums[i] + 1):
# 遍历 k,如果已经大于背包容量直接跳出循环
if k * weights[i] > j:
break
dp[j] = max(dp[j], dp[j - weights[i] * k] + values[i] * k)
print(dp[-1])