作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。
多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。
欢迎 点赞✍评论⭐收藏
算法领域知识
链接 | 专栏 |
---|---|
分发糖果 | 算法专栏 |
买卖股票的最佳时机 | 算法专栏 |
经典算法题 之 买卖股票的最佳时机
题目如下:
给你一个整数数组 prices
,其中 prices[i]
表示某支股票第 i
天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4] 输出:7 解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。 总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 总利润为 4 。
示例 3:
输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
提示:
1 <= prices.length <= 3 * 10
40 <= prices[i] <= 10
4解答这道题,可以使用
贪心算法
进行解决。
我们遍历数组,寻找股票价格上升的机会,并在最低价格时买入,最高价格时卖出。 我们维护一个变量profit来存储最大利润。在遍历的过程中,我们更新最小价格和最大利润。
算法的实现逻辑如下:
以下是用Java代码实现逻辑的示例:
public int maxProfit(int[] prices) {
int minPrice = prices[0]; // 初始化最小价格
int maxProfit = 0; // 初始化最大利润
for (int i = 1; i < prices.length; i++) {
if (prices[i] < minPrice) { // 当前价格比最小价格小
minPrice = prices[i]; // 更新最小价格
} else if (prices[i] - minPrice > maxProfit) { // 当前利润大于最大利润
maxProfit = prices[i] - minPrice; // 更新最大利润
}
}
return maxProfit;
}
如果你想要继续优化算法,可以考虑将上述算法转化为动态规划算法。
这种方法使用两个变量来跟踪当前的最小值和最大差值。
我们从第二个元素开始遍历,用当前元素的值减去前面的最小值来更新最大差值。需要注意,这里取最小值的时候,我们需要在前面的所有元素中选出最小值。
算法的实现逻辑如下:
以下是用Java代码实现逻辑的示例:
public int maxProfit(int[] prices) {
int minPrice = prices[0]; // 初始化最小值
int maxProfit = 0; // 初始化最大差值
for (int i = 1; i < prices.length; i++) {
int curProfit = prices[i] - minPrice; // 计算当前差值
if (prices[i] < minPrice) { // 更新最小值
minPrice = prices[i];
}
if (curProfit > maxProfit) { // 更新最大差值
maxProfit = curProfit;
}
}
return maxProfit;
}
由于遍历了整个数组,时间复杂度为 O(n),空间复杂度为 O(1)。
如果我们要将这个问题扩展到允许进行 k 次交易,我们还可以使用动态规划算法来解决。
我们可以为每个交易次数和每个价格点都维护一些变量,以解决这个问题。使用一个二维数组 dp,其中 dp[i][j] 表示在第 i 天结束时,最多进行 j 次交易所能获得的最大利润。
我们需要和之前的算法一样,使用一个 Profit 变量来维护最大差值,以便在更新 dp 数组时使用。对于每一天,我们需要遍历之前的一天中的所有可能交易次数,并在其中选出最大的利润。此外,我们需要确保交易次数 j 不会超过 i/2,因为在同一天内进行的交易分别计算为一次买入和一次卖出,所以最多可以进行 i/2 次交易。
算法的实现逻辑如下:
以下是用Java代码实现逻辑的示例:
public int maxProfit(int k, int[] prices) {
if (k == 0) {
return 0; // 不允许进行交易
}
int n = prices.length;
if (k >= n / 2) {
// 交易次数太多,相当于在每一天都可以买入和卖出
int maxProfit = 0;
for (int i = 1; i < n; i++) {
if (prices[i] > prices[i-1]) {
maxProfit += prices[i] - prices[i-1];
}
}
return maxProfit;
}
int[][] dp = new int[k+1][n]; // 初始化 dp 数组为 0
for (int i = 1; i <= k; i++) { // 对于每个交易次数
int maxProfit = -prices[0]; // 初始化 Profit 为 -prices[0]
for (int j = 1; j < n; j++) { // 遍历每天
dp[i][j] = Math.max(dp[i][j-1], maxProfit + prices[j]); // 更新 dp 值
maxProfit = Math.max(maxProfit, dp[i-1][j-1] - prices[j]);
}
}
return dp[k][n-1]; // 返回 k 次交易中在最后一天可以获得的最大利润
}
由于遍历了整个数组,时间复杂度为 O(kn),空间复杂度为 O(kn)。
关注作者,普修罗双战士,给你不一样的技术体验,一起在技术领域扶摇直上九万里,共筑坚如磐石的权。
欢迎 点赞✍评论⭐收藏