刷题:80、股票市场交易策略优化 | 豆包MarsCode AI刷题

44 阅读4分钟

问题描述

小R近期表现出色,公司决定以股票的形式给予奖励,并允许他在市场上进行交易以最大化收益。给定一个数组,数组中的第 i 个元素代表第 i 天的股票价格。小R需要设计一个算法来实现最大利润。

股票交易规则如下:

  • 小R可以多次买卖股票,但在买入新的股票前必须卖出之前的股票。
  • 每次卖出股票后存在一天的冷冻期,在冷冻期内小R不能购买股票。

你的任务是帮助小R计算出在遵守交易规则的情况下能够获得的最大利润。

  • stocks: 一个整数列表,表示连续几天内的股票价格。

测试样例

样例1:

输入:stocks = [1, 2]
输出:1

样例2:

输入:stocks = [2, 1]
输出:0

样例3:

输入:stocks = [1, 2, 3, 0, 2]
输出:3

样例4:

输入:stocks = [2, 3, 4, 5, 6, 7]
输出:5

样例5:

输入:stocks = [1, 6, 2, 7, 13, 2, 8]
输出:12

解题思路

动态规划

1、dp 数组的含义

dp[i][j]:第 i 天状态为j,获得的最大利润。

根据题目描述,由于最多只能同时买入(持有)一支股票,并且卖出股票后有冷冻期的限制,设置了四种不同的状态

  • dp[i][0]:目前持有一支股票;
  • dp[i][1]:目前不持有任何股票(可能在冷冻期,可能不在冷冻期);
  • dp[i][2]:当天卖出股票;
  • dp[i][3]:目前为冷冻期状态,但冷冻期状态不可持续,只有一天!

2、状态转移方程

1)对于 dp[i][0],有两种可能的情况:
  • 操作一:前一天就是持有股票状态(延续),dp[i][0] = dp[i - 1][0]
  • 操作二:今天买入了,有两种情况
    • 前一天是冷冻期,dp[i - 1][3] - stocks[i]
    • 前一天是保持卖出股票的状态,dp[i - 1][1] - stocks[i]

那么 dp[i][0] = max(dp[i - 1][0], dp[i - 1][3] - stocks[i], dp[i - 1][1] - stocks[i]);

2)对于dp[i][1],有两种可能的情况:
  • 操作一:前一天就是不持有股票状态
  • 操作二:前一天是冷冻期

dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);

3)对于dp[i][2] ,只有一个操作:

昨天一定是持有股票状态,今天卖出股票。

即:dp[i][2] = dp[i - 1][0] + stocks[i];

4)dp[i][3],只有一个操作:

昨天卖出了股票,今天是冷冻期。

dp[i][3] = dp[i - 1][2];

3、细节

可以将第 0 天的情况作为动态规划中的边界条件

dp[0][0] = -stocks[0];

在第 0 天时,如果持有股票,那么只能是在第 0 天买入的,对应负收益 −stocks[0],如果不持有股票,那么收益为零。这样就可以从第 1 天开始,根据上面的状态转移方程进行进行动态规划,直到计算出第 n−1 天的结果。

4、代码实现

public static int solution(int[] stocks) {
        if (stocks == null || stocks.length < 2) {
            return 0;
        }
        int len = stocks.length;
        int[][] dp = new int[stocks.length][4];

        // 初始化
        dp[0][0] = -stocks[0];

        for (int i = 1; i < stocks.length; i++) {
            // dp公式
            dp[i][0] = Math.max(Math.max(dp[i - 1][0], dp[i - 1][1] - stocks[i]), dp[i - 1][3] - stocks[i]);
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][3]);
            dp[i][2] = dp[i - 1][0] + stocks[i];
            dp[i][3] = dp[i - 1][2];
        }

        return Math.max(Math.max(dp[len - 1][1], dp[len - 1][2]), dp[len - 1][3]);
    }
时间复杂度

时间复杂度:O(n)

空间复杂度:O(n)

学习心得

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。 所有动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。

  • 动态规划问题需要清晰地定义状态和状态转移方程;
  • 空间优化是解决动态规划问题时减少资源消耗的有效方法;
  • 在实际应用中,需要考虑边界条件,例如本题中的数组长度小于2的情况。

知识点延伸

  • 动态规划:这是一种解决决策问题的算法思想,通过将问题分解为更小的子问题来解决原问题。
  • 空间优化:在动态规划中,可以使用滚动数组或变量来减少空间复杂度。
  • 股票问题系列:在LeetCode等平台上,有许多关于股票买卖的问题,它们都可以用动态规划来解。