Dynamic Programming学习笔记 (28) - 买卖股票的最佳时机 (力扣# 121)

206 阅读2分钟

本题出自力扣题库第121题。题面大意如下:

给定一个长度为N的数组 prices,它的第i个元素 prices[i] 表示股票第i天的价格。 选择某一天买入股票,并选择在未来的某一个不同的日子卖出。 计算所能获取的最大利润。如果你不能获取任何利润,返回0。

示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第2天(股票价格 = 1)买入,在第5天(股票价格 = 6)卖出,最大利润 = 6-1 = 5 。

示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有盈利的可能, 所以返回 0。

解题思路:

在本题中,股票买卖必须是多头操作,也就是也买再卖,以N=5为例,所有可能的组合是

prices[0]买,  prices[1]卖,  利润 = prices[1] - prices[0]             
prices[0]买,  prices[2]卖,  利润 = prices[2] - prices[0]             
prices[0]买,  prices[3]卖   利润 = prices[3] - prices[0]
prices[0]买,  prices[4]卖   利润 = prices[4] - prices[0]

prices[1]买,  prices[2]卖   利润 = prices[2] - prices[1]
prices[1]买,  prices[3]卖   利润 = prices[3] - prices[1]
prices[1]买,  prices[4]卖   利润 = prices[4] - prices[1]

prices[2]买,  prices[3]卖   利润 = prices[3] - prices[2]
prices[2]买,  prices[4]卖   利润 = prices[4] - prices[2]

prices[3]买,  prices[4]卖   利润 = prices[4] - prices[3]

要找的是以上组合中利润最大的一个。常规方法是使用双层循环来穷举所有的可能并找到最大值,其时间复杂度为O(N*N),使用DP思路,我们可以将上面的列表重新组合

prices[0]买,  prices[1]卖,  利润 = prices[1] - prices[0]             

prices[0]买,  prices[2]卖,  利润 = prices[2] - prices[0]             
prices[1]买,  prices[2]卖   利润 = prices[2] - prices[1]

prices[0]买,  prices[3]卖   利润 = prices[3] - prices[0]
prices[1]买,  prices[3]卖   利润 = prices[3] - prices[1]
prices[2]买,  prices[3]卖   利润 = prices[3] - prices[2]

prices[0]买,  prices[4]卖   利润 = prices[4] - prices[0]
prices[1]买,  prices[4]卖   利润 = prices[4] - prices[1]
prices[2]买,  prices[4]卖   利润 = prices[4] - prices[2]
prices[3]买,  prices[4]卖   利润 = prices[4] - prices[3]

这时我们就可以看到, 对于某个给定的一天来说,当天可能获得的最大利润就是当天的价格减去之前所有价格中最小的一个。从这个思路出发,我们就可以实现一个O(N)的线性算法。该算法称为Kadane算法,由卡内基梅隆大学的Jay Kadane提出。

Java代码如下:

class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length < 2) {
            return 0;
        }

        int minBuyPrice = prices[0];
        int maxProfit = 0;

        for (int i = 1; i < prices.length; i ++) {
            int profit = prices[i] - minBuyPrice;
            maxProfit = Math.max(maxProfit, profit);

            minBuyPrice = Math.min(minBuyPrice, prices[i]);
        }

        return maxProfit;
    }
}