卖股票的最佳时机II[贪心 || 动态规划]

81 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,卖股票的最佳时机II[贪心 || 动态规划] - 掘金 (juejin.cn)

前言

卖股票的最佳时机,我们可以看其全貌进行股票交易,不会说错过了昨天今天就不能操作了,可采用贪心进行假买假卖。这也是经典的动态规划练习题,持有/不持有股票两种状态,每天的两种状态都是前一天的两种状态转移过来,取最大即可。

一、卖股票的最佳时机

image.png

二、贪心 & 状压动规

1、贪心

// 先分析思考,并记录思路,再coding,拒绝秒杀,希望有一个思考分析记录的锻炼过程。
    /*
    只要碰到股票比前一天下跌了就卖出去(贪心点),当前后形成逆序,其实是一个假买假卖的动作,即今天判断,却以昨天的状态卖了。
    假买假卖,其实当天没有买,因为收益没有减去buyPrices,其实当前没有卖,而是想着该前一天把他卖了。站在未来的视角,却做着昨天的事。
    */
    public int maxProfit(int[] prices) {
        int buyPrice = prices[0];
        int sumProfit = 0;

        for(int i = 1;i < prices.length;i++){
            // 如果股票开始跌了,马上卖。
            if(prices[i] < prices[i - 1]) {
                sumProfit += prices[i - 1] - buyPrice;
                // 新一次手持股票价格
                buyPrice = prices[i];
            }
        }
        // 正常结束循环,需要把股票卖了,才会增加一笔收益。
        return sumProfit + prices[prices.length - 1] - buyPrice;
    }

2、状压动规

状态定义:f[i]第i天的收益;

第i天有什么状态?持有股票和不持有股票 -> f[i][2];

第i天持有/不持有股票的收益如何得到?前一天持有/前一天不持有 + 买卖股票得来;

最终状态:f[n - 1][0]:最后一天不持有股票时的收益。

// 每天可持有股票和不持有股票两种状态,而当天是否持有股票和前一天持有/不持有股票的收益有关。
    public int maxProfit(int[] prices) {
        int[] f = new int[2];// 持有和不持有股票,由于前后相关,所以状态降维。
    
        f[1] = -prices[0];
        
        for(int i = 1;i < prices.length;i++){
            int old = f[0];
            
            f[0] = Math.max(old,f[1] + prices[i]);// 看卖了是否不如当初就不买。
            f[1] = Math.max(f[1],old - prices[i]);// 看是持有那天的股票才是收益最高的。
        }
        return f[0];
    }

总结

1)贪心问题,分析贪心点所在,进行问题转换,再选择合适的数据结构与经典的算法思想,完成题解。

2)动态规划,本质将大问题分解成规模更小但性质相同的递推问题,分析并抓住各种状态 & 状态定义(记录什么时候的效果,如第i天持有股票的收益) & 状态的转移关系 & 最终状态。

3)先分析思考,并记录思路,再coding,拒绝秒杀,希望有一个思考分析记录的锻炼过程。

参考文献

[1] LeetCode 卖股票的最佳时机II