当前位置 博文首页 > Yawn:Leetcode——买卖股票的最佳时机

    Yawn:Leetcode——买卖股票的最佳时机

    作者:[db:作者] 时间:2021-08-02 15:46

    1. 题目

    给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

    你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

    返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

    在这里插入图片描述

    2. 题解

    原则就是, 记录当前最小的值,逐一比较

    解法一:

    双指针:

    • 记录数组中访问过的最小值
    • 记录最大值,默认为0
    • 循环数组,计算当前值与最小值的差距
    class Solution {
        public int maxProfit(int[] prices) {
            if( prices == null || prices.length == 0)
                return 0;
            int max = 0, min = prices[0];   //数组中访问过的最小值
            for(int i = 0; i < prices.length; i++){
                min = Math.min(min, prices[i]);
                max = Math.max(max, prices[i] - min);
            }
            return max;
        }
    }
    

    解法二:

    动态规划:

    • 确定状态
    • 找到转移公式
    • 确定初始条件以及边界条件
    • 计算结果

    定义一个二维数组 dp[length][2],其中 dp[i][0] 表示第 i+1 天( i是从0开始的)结束的时候没持有股票的最大利润,dp[i][1] 表示第 i+1 天结束的时候持有股票的最大利润。

    如果我们要求第 i+1 天结束的时候没持有股票的最大利润dp[i][0],那么会有两种情况。

    • 第一种情况就是第 i+1 天我们即没买也没卖,那么最大利润就是第i天没持有股票的最大利润 dp[i-1][0]。
    • 第二种情况就是第 i+1 天我们卖了一支股票,那么最大利润就是第i天持有股票的最大利润(这个是负的,并且也不一定是第i天开始持有的,有可能在第i天之前就已经持有了)加上第i+1天卖出股票的最大利润,dp[i-1][1]+prices[i]

    很明显我们可以得出
    dp[i][0] = max(dp[i-1][0], dp[i-1][1]+prices[i]);

    同理我们可以得出第i+1天结束的时候我们持有股票的最大利润
    dp[i][1] = max(dp[i-1][1], -prices[i]);

    边界条件就是第1天的时候,如果我们不持有股票,那么
    dp[0][0] = 0;

    如果持有股票,那么
    dp[0][1] = -prices[0];

    有了边界条件和递推公式,代码就很容易写出来了,来看下代码

    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0)
            return 0;
        int length = prices.length;
        int[][] dp = new int[length][2];
        //边界条件
        dp[0][0]= 0;
        dp[0][1] = -prices[0];
        for (int i = 1; i < length; i++) {
            //递推公式
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
            dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
        }
        //毋庸置疑,最后肯定是手里没持有股票利润才会最大,也就是卖出去了
        return dp[length - 1][0];
    }
    

    优化代码:

    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0)
            return 0;
        int length = prices.length;
        int hold = -prices[0];//持有股票
        int noHold = 0;//不持有股票
        for (int i = 1; i < length; i++) {
            //递推公式
            noHold = Math.max(noHold, hold + prices[i]);
            hold = Math.max(hold, -prices[i]);
        }
        //毋庸置疑,最后肯定是手里没持有股票利润才会最大,
        //也就是卖出去了
        return noHold;
    }
    

    解法三:

    单调栈:

    • 始终保持栈顶元素是所访问过的元素中最小的,如果当前元素小于栈顶元素,就让栈顶元素出栈,让当前元素入栈。
    • 如果访问的元素大于栈顶元素,就要计算他和栈顶元素的差值,我们记录最大的即可
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0)
            return 0;
        Stack<Integer> stack = new Stack<>();
        stack.push(prices[0]);
        int max = 0;
        for (int i = 1; i < prices.length; i++) {
            //如果栈顶元素大于prices[i],那么栈顶元素出栈,
            //把prices[i]压栈,要始终保证栈顶元素是最小的
            if (stack.peek() > prices[i]) {
                stack.pop();
                stack.push(prices[i]);
            } else {
                //否则如果栈顶元素不大于prices[i],就要计算
                //prices[i]和栈顶元素的差值
                max = Math.max(max, prices[i] - stack.peek());
            }
        }
        return max;
    }
    
    cs
    下一篇:没有了