🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
⭐动态规划⭐
🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
前言
动态规划(Dynamic Programming, DP)是一种在计算机科学和数学中用于解决最优化问题的方法。它特别适用于可以分解为互相重叠的子问题的问题,并且这些子问题的解可以被存储起来以避免重复计算,从而提高效率。
动态规划的基本思想
- 最优子结构:问题的最优解包含了其子问题的最优解。
- 重叠子问题:求解过程中,子问题被重复计算多次。
动态规划的步骤
- 确定状态:定义问题的状态表示,即用一组变量来描述问题的关键特征。
- 状态转移方程:找到如何从一个状态转移到另一个状态的规则或公式。
- 边界条件:定义初始状态或基本情况,这是递归终止的条件。
- 计算顺序:确定解决问题的顺序,通常是自底向上或自顶向下
实现方式
动态规划可以通过两种主要的方式来实现:
- 自顶向下(递归 + 记忆化):从问题的大状态开始,逐步递归到小状态,使用记忆表来存储中间结果。
- 自底向上(迭代):从最小的状态开始,逐步构建更大的状态直到达到最终的目标状态。
示例
假设我们要解决斐波那契数列问题第 n 个斐波那契数 F(n) = F(n-1) + F(n-2),F(0) = 0, F(1) = 1。
自顶向下方法:
1def fibonacci(n, memo={}):
2 if n in memo:
3 return memo[n]
4 if n <= 1:
5 return n
6 memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
7 return memo[n]
自底向上方法:
1def fibonacci(n):
2 if n <= 1:
3 return n
4 prev, curr = 0, 1
5 for i in range(2, n+1):
6 prev, curr = curr, prev + curr
7 return curr
回溯算法是⼀种⾮常重要的算法,可以解决许多组合问题、排列问题和搜索问题等。回溯算法的核⼼ 思想是搜索状态树,通过遍历状态树来实现对所有可能解的搜索。回溯算法的模板⾮常简单,但是实 现起来需要注意⼀些细节,⽐如如何做出选择、如何撤销选择等。
2. 买卖股票的最佳时机III(hard)
题目链接:123. 买卖股票的最佳时机 III - 力扣(LeetCode)
算法思路:
问题描述
给定一个整数数组
prices
,其中prices[i]
是第i
天的股票价格,以及一个整数k
表示允许的最大交易次数,目标是计算最多进行k
次交易可以获得的最大利润。状态表示
定义两个二维数组
f
和g
,其中:
f[i][j]
表示第i
天结束后,已完成j
次交易且处于“买入”状态时的最大利润。g[i][j]
表示第i
天结束后,已完成j
次交易且处于“卖出”状态时的最大利润。状态转移方程
对于每个状态
f[i][j]
和g[i][j]
,我们需要考虑如何从前一天的状态转移过来。对于
f[i][j]
:
f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i])
,
f[i - 1][j]
表示第i
天什么也不做,保持买入状态。g[i - 1][j] - prices[i]
表示第i
天买入股票。对于
g[i][j]
:
g[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + prices[i])
,其中j >= 1
,
g[i - 1][j]
表示第i
天什么也不做,保持卖出状态。f[i - 1][j - 1] + prices[i]
表示第i
天卖出股票,完成第j
次交易。初始化
- 当
i = 0
时,只能处于“买入”状态,即f[0][0] = -prices[0]
。- 其他所有不存在的状态初始化为足够小的值
-INF
(例如-0x3f3f3f3f
),以确保不会干扰后续的最大值计算。填表顺序
- 按照日期顺序从前往后填充表格。
- 对于每一天,先填充
f[i]
再填充g[i]
,且从交易次数j = 1
开始逐次增加。返回值
- 返回
g
表最后一行的最大值作为答案。
代码实现:
class Solution {
public int maxProfit(int[] prices) {
// 1.创建dp表
// 这里使用到 f(i,j)表示第i天已完成j笔交易此时是买入状态,g(i,j)表示第i天已完成j笔交易此时是卖出状态
int INF = 0x3f3f3f3f; // 这里最小值运用 INTEGER.MIN/2
int n = prices.length;
if (n <= 1) {
return 0;
}
int[][] f = new int[n][3];
int[][] g = new int[n][3];
// 2.初始化
for (int j = 0; j < 3; j++) {
f[0][j] = -INF;
g[0][j] = -INF;
}
f[0][0] = -prices[0];
g[0][0] = 0;
// 3.填表
for (int i = 1; i < n; i++) {
for (int j = 0; j < 3; j++) {
f[i][j] = Math.max(f[i - 1][j], g[i - 1][j] - prices[i]);
g[i][j] = g[i - 1][j];
if (j - 1 >= 0) {
g[i][j] = Math.max(g[i][j], f[i - 1][j - 1] + prices[i]);
}
}
}
// 4.返回值
int ret = -1;
for (int j = 0; j < 3; j++)
ret = Math.max(ret, g[n - 1][j]);
return ret;
}
}
总结
动动手点个赞会让作者更开心,感谢阅览,加油哇各位 !