mirror of
https://github.com/SunnyQjm/algorithm-review.git
synced 2026-06-03 08:16:43 +08:00
add: chapter8
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#######################################################################################
|
||||
# 背包问题
|
||||
#
|
||||
# 给你一个可装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。其中第 i 个
|
||||
# 物品的重量为wt[i],价值为 val[i],现在让你用这个背包装物品,最多能装的价值是多少?
|
||||
#
|
||||
#######################################################################################
|
||||
|
||||
class Solution:
|
||||
def knapsack(self, W, N, wt, val):
|
||||
"""
|
||||
:type W:int
|
||||
:type N:int
|
||||
:type wt:[int]
|
||||
:type val:[int]
|
||||
:rtype int
|
||||
|
||||
思路:
|
||||
1. 使用动态规划;
|
||||
2. 定义状态:dp[i][w] => 表示只放前i个物品,且背包容量为w的情况下,最多能装的价值;
|
||||
3. base case => dp[0][...]和dp[...][0]都应该为0,表示没有物品可放或者背包容量为0的情况下,能装的价值自然为0;
|
||||
4. 状态转移方程:
|
||||
f(i, w) = 0 i == 0 || w == 0
|
||||
= f(i - 1, w) i > 0 && w > 0 && wt[i] > w => 如果一个物品的重量都大于背包的重量了,肯定不能放进背包
|
||||
= max{f(i - 1, w), f(i - 1, w - wt[i]) + val[i]} i > 0 && w > 0 && wt[i] <= w => 根据放或者不放第i个物品,取最大价值
|
||||
|
||||
tip: 可以参考 => https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/bei-bao-wen-ti
|
||||
"""
|
||||
dp = [[0] * (W + 1) for i in range(N + 1)]
|
||||
for i in range(1, N + 1):
|
||||
for w in range(1, W + 1):
|
||||
if wt[i - 1] > w:
|
||||
dp[i][w] = dp[i - 1][w]
|
||||
else:
|
||||
dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - wt[i - 1]] + val[i - 1]);
|
||||
return dp[N][W]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.knapsack(4, 3, [2, 1, 3], [4, 2, 3]), "= 6")
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#######################################################################################
|
||||
# 投资问题
|
||||
#
|
||||
# 设有m元钱,n项投资,函数 fi(x) 表示将x元钱投入到第 i 项项目所产生
|
||||
# 的效益,i=1,…, n. 问:如何分配这m元钱,使得投资的总效益最高?
|
||||
#######################################################################################
|
||||
|
||||
class Solution:
|
||||
def investmentProblem(self, f, m):
|
||||
"""
|
||||
:type f: List[List[int]]
|
||||
:type m: int
|
||||
:rtype int
|
||||
|
||||
思路:
|
||||
1. 采用动态规划的思路解;
|
||||
2. 定义状态:dp[i][j] => 表示前i个项目投资j元所能获得的最大收益;
|
||||
3. base case => dp[0][...]和dp[...][0]均为0,表示没有项目或者投资金额为0时,收益自然为0;
|
||||
4. 状态转移方程:
|
||||
F(i, j) = f(i, j) i == 1 => 当只投资一个项目时,直接返回投资j元到该项目的收益即为总收益
|
||||
= max(0 <= k <= j){F(i - 1, j - k) + f(i, k)} i > 1 => 前i个项目投资j元的总收益可以化解为以下子问题:
|
||||
- 前i - 1个项目投资0元,第i个项目投资j元;
|
||||
- 前i - 1个项目投资1元,第i个项目投资j - 1元;
|
||||
- ...
|
||||
- 前i - 1个项目投资j元,第i个项目投资0元;
|
||||
取上述所有子问题的最大的值即可。
|
||||
"""
|
||||
# 获取项目的个数
|
||||
num = len(f)
|
||||
dp = [[0] * (m + 1) for i in range(num + 1)]
|
||||
|
||||
# 处理i==1,即只投资一个项目的情况
|
||||
for j in range(1, m + 1):
|
||||
dp[1][j] = f[0][j]
|
||||
|
||||
for i in range(2, num + 1):
|
||||
for j in range(1, m + 1):
|
||||
for k in range(j):
|
||||
dp[i][j] = max(dp[i][j], dp[i - 1][j - k] + f[i - 1][k])
|
||||
return dp[-1][-1]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.investmentProblem(
|
||||
[
|
||||
[0, 11, 12, 13, 14, 15],
|
||||
[0, 0, 5, 10, 15, 20],
|
||||
[0, 2, 10, 30, 32, 40],
|
||||
[0, 20, 21, 22, 23, 24]
|
||||
],
|
||||
5
|
||||
), "= 61")
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#######################################################################################
|
||||
# Leetcode 746 使用最小花费爬楼梯
|
||||
#
|
||||
# 数组的每个索引作为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 cost[i](索引从0开始)。
|
||||
# 每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。
|
||||
# 您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: cost = [10, 15, 20]
|
||||
# 输出: 15
|
||||
# 解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
|
||||
# 输出: 6
|
||||
# 解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。
|
||||
#
|
||||
# 注意:
|
||||
# 1. cost 的长度将会在 [2, 1000]。
|
||||
# 2. 每一个 cost[i] 将会是一个Integer类型,范围为 [0, 999]。
|
||||
#######################################################################################
|
||||
|
||||
class Solution:
|
||||
def minCostClimbingStairs(self, cost):
|
||||
"""
|
||||
:type cost: List[int]
|
||||
:rtype: int
|
||||
|
||||
思路:
|
||||
题目中其实cost[i]表示如果要站在第i个阶梯上,需要付出的代价,然后隐含了一个楼层顶部其实是一个代价为0的虚拟阶梯
|
||||
1. 使用动态规划;
|
||||
2. 定义状态:dp[i] => 到达第i个台阶所需的最小花费;(i从0~len(cost))
|
||||
3. base case => dp[0] = cost[0], dp[1] = cost[1]
|
||||
4. 状态转移方程:
|
||||
f(i) = cost[i] i == 0 || i == 1
|
||||
min{cost[i - 1] + cost[i], cost[i - 2] + cost[i]} i > 1
|
||||
"""
|
||||
|
||||
# 最末尾添加一个开销为0的虚拟阶梯,代表楼顶,我们的目标就是要到达这个楼顶
|
||||
cost.append(0)
|
||||
for i in range(2, len(cost)):
|
||||
cost[i] = cost[i] + min(cost[i - 1], cost[i - 2])
|
||||
return cost[-1]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.minCostClimbingStairs([10, 15, 20]), "= 15")
|
||||
print(solution.minCostClimbingStairs([1, 100, 1, 1, 1, 100, 1, 1, 100, 1]), "= 6")
|
||||
Reference in New Issue
Block a user