Leetcode 188. 买卖股票的最佳时机 Ⅳ 状态机dp C++实现

Leetcode 188.买卖股票的最佳时机 Ⅳ

问题:给你一个整数数组 prices 和一个整数 k ,其中 prices[i] 是某支给定的股票在第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多可以买 k 次,卖 k 次。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

算法:递归搜索 + 保存计算结果 = 记忆化搜索

        在 Leetcode122. 买卖股票 状态机dp C++实现 的基础上,添加一个参数 j,表示当前可以至多交易 j 次。

注意:由于最后未持有股票,手上的股票一定会卖掉,所以代码中的 j-1 可以是在买股票的时候,也可以是在卖股票的时候,这两种写法都是可以的。

以下代码参数 j 的修改时机为买入时。

时间复杂度:O(nk),其中 n 为 prices 的长度。

空间复杂度:O(nk)

代码:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        vector<vector<array<int, 2>>> memo(n, vector<array<int, 2>>(k + 1, {-1, -1})); // -1 表示还没有计算过
        auto dfs = [&](auto&& dfs, int i, int j, bool hold) -> int {
            if (j < 0)  return INT_MIN / 2; // 除 2 防止溢出
            if (i < 0)  return hold ? INT_MIN / 2 : 0;

            int& res = memo[i][j][hold]; // 注意这里是引用
            if (res != -1)  return res;// 之前计算过
            if (hold)   return res = max(dfs(dfs, i - 1, j, true), dfs(dfs, i - 1, j - 1, false) - prices[i]);
            return res = max(dfs(dfs, i - 1, j, false), dfs(dfs, i - 1, j, true) + prices[i]);
        };
        return dfs(dfs, n - 1, k, false);
    }
};

算法:1:1 翻译成递推

时间复杂度:O(nk),其中 n 为 prices 的长度。

空间复杂度:O(nk)

代码:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        vector<vector<array<int, 2>>> dp(n + 1, vector<array<int, 2>>(k + 2, {INT_MIN / 2, INT_MIN / 2}));
        for(int j = 1;j <= k + 1;j++)   dp[0][j][0] = 0;
        for(int i = 0;i < n;i++)
            for(int j = 1;j <= k + 1;j++){
                dp[i + 1][j][0] = max(dp[i][j][0],dp[i][j][1] + prices[i]);
                dp[i + 1][j][1] = max(dp[i][j][1],dp[i][j - 1][0] - prices[i]);
            }
            return dp[n][k + 1][0];
    }
};

算法:空间优化

必须倒序遍历。

时间复杂度:O(nk),其中 n 为 prices 的长度。

空间复杂度:O(k)

代码:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        vector<array<int, 2>> dp(k + 2, {INT_MIN / 2, INT_MIN / 2});
        for(int j = 1;j <= k + 1;j++)   dp[j][0] = 0;
        for(int p : prices)
            for(int j = k + 1;j > 0;j--){
                dp[j][0] = max(dp[j][0],dp[j][1] + p);
                dp[j][1] = max(dp[j][1],dp[j - 1][0] - p);
            }
            return dp[k + 1][0];
    }
};
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值