Leetcode122. 买卖股票 状态机dp C++实现

Leetcode 122. 买卖股票的最佳时机

问题:给你一个整数数组 prices ,其中 prices [ i ] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。返回你能获得的最大利润 。


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

        每天可以有两种状态,持有股票或未持有股票,所对应的状态转移方程也不同,如下图。

        从后向前递归,递归边界是第 0 天时,第 0 天不可能持有股票,但是递归过程中,会出现第 0 天的状态是 hold(持有)的情况,所以我们把这种情况的返回值设置成 INT_MIN ,这样就不会影响最后的输出。

        递归入口是第 n 天时,由于第 n 天时未持有股票一定比持有股票利润大,所以递归入口状态设置成 false(未持有)。

代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<array<int,2>> memo(n,{-1,-1});
        auto dfs = [&](auto &&dfs,int i,bool hold){
            if(i < 0)   return hold ? INT_MIN : 0; // INT_MIN 是因为第0天不可能持有股票,此时我们return一个最小值来保证其他递归的正确性
            int& res = memo[i][hold];
            if(res != -1)   return res;// 之前被计算过了
            if(hold)    return res = max(dfs(dfs,i-1,true),dfs(dfs,i-1,false) - prices[i]); // 当天持有
            return res = max(dfs(dfs,i-1,false),dfs(dfs,i-1,true) + prices[i]); // 当天未持有
        };
        return dfs(dfs,n-1,false); // 递归入口
    }
};

算法2:1:1 翻译成递推

        创建二维数组 dp ,并给 dp [ 0 ] [ 1 ] 赋初始值 INT_MIN ,遍历,列出状态转移方程。

代码:

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

算法3:空间优化

        算法1算法2 可知,我们在使用 dp 数组时只用到了相邻的两个格子,所以为了节省空间,我们可以不使用数组,仅使用变量来存储数据。dp0 表示未持有股票的利润,dp1 表示当前持有股票的利润。

代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int dp0 = 0,dp1 = INT_MIN;
        for(int p : prices){
            int new_dp0 = max(dp0,dp1 + p);
            dp1 = max(dp1,dp0 - p);
            dp0 = new_dp0;
        }
        return dp0;
    }
};

算法4:

遍历数组,与标记到的最低价进行比较,画一个折线图,将所有的上升(红色)线段加起来即可得到答案。

代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size(),ans = 0;
        for(int i = n - 1;i > 0;i--)    prices[i] -= prices[i - 1];
        prices[0] = 0;
        for(int p : prices)
            if(p > 0)   ans += p;
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值