动态规划,股票买卖最佳时机:六道题目

本文深入解析了六个股票买卖问题的最优时机算法,包括121-123题的动态规划解法,以及309、188和714题的扩展,展示了如何利用贪心、空间优化等技巧求解。

股票买卖最佳时机

一、121. 买卖股票的最佳时机

在一个数组中找到两个值:后一个值减去前一个值,差值最大。

解法一:暴力法,(时间超限制)

    public int maxProfit(int[] prices) {
        int res = 0;
        for (int i=0; i<prices.length-1; i++) {
            for (int j=i+1; j<prices.length; j++) {
                if (prices[j]-prices[i]>res) {
                    res = prices[j] - prices[i];
                }
            }
        }
        return res;
    }

解法二:一次遍历

    public int maxProfit(int[] prices) {
        int minV = Integer.MAX_VALUE;
        int res = 0;
        for (int i=0; i<prices.length; i++) {
            if (minV>prices[i]) {
                minV = prices[i];
            }else if (prices[i]-minV>res) {
                res = prices[i]-minV;
            }
        }
        return res;
    }

解法三:动态规划(二维数组)

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        // dp[i][0] 不持有股票、dp[i][1] 持有股票
        int[][] dp = new int[n][2];
        dp[0][0] = 0;
        dp[0][1] = 0-prices[0];
        for (int i=1; i<prices.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[n-1][0];
    }

解法四:动态规划(空间复杂度的优化一)

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        int[][] dp = new int[2][2];
        // dp[i][0] 不持有股票, dp[i][1] 持有股票
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        for (int i=1; i<n; i++) {
            dp[i%2][0] = Math.max(dp[(i-1)%2][0], dp[(i-1)%2][1]+prices[i]);
            dp[i%2][1] = Math.max(-prices[i], dp[(i-1)%2][1]);
        }
        return dp[(n+1)%2][0];
    }

解法五:动态规划(空间复杂度的优化二)

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        int notGP = 0;
        int hasGP = -prices[0];
        for (int i=1; i<n; i++) {
            notGP = Math.max(notGP, hasGP+prices[i]);
            hasGP = Math.max(-prices[i], hasGP);
        }
        return notGP;
    }

二、122. 买卖股票的最佳时机 II

2.1 解法一:贪心算法

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        int res = 0;
        for (int i=1; i<n; i++) {
            if (prices[i]>prices[i-1]) {
                res += prices[i]-prices[i-1];
            }
        }
        return res;
    }

2.2 解法二:动态规划

dp[i][0] 持有现金;dp[i][1] 持有股票

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        int[][] dp = new int[n][2];
        // 持有股票
        dp[0][0] = 0;
        // 持有现金
        dp[0][1] = -prices[0];
        for (int i=1; i<n; 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], dp[i-1][0]-prices[i]);
        }
        return dp[n-1][0];
    }

2.3 解法三:动态规划(空间复杂度优化)

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        int notGP = 0;
        int hasGP = -prices[0];
        for (int i=1; i<n; i++) {
            int tNotGP = notGP;
            notGP = Math.max(notGP, hasGP+prices[i]);
            hasGP = Math.max(hasGP, tNotGP-prices[i]);
        }
        return notGP;
    }

三、123. 买卖股票的最佳时机 III

3.1 解法一:转换成第一题(时间超限制)

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        int res = 0;
        for (int i=1; i<n; i++) {
            int leftRes = subMax(0, i, prices);
            int rightRes = subMax(i+1, n-1, prices);
            res = Math.max(res, leftRes + rightRes);
        }
        return res;
    }

    /**
     * 查询自结果
     */
    private int subMax(int lo, int hi, int[] prices) {
        if (lo>=hi) return 0;
        int notGP=0;
        int hasGP=-prices[lo];
        for (int i=lo+1; i<=hi; i++) {
            notGP = Math.max(notGP, hasGP+prices[i]);
            hasGP = Math.max(hasGP, -prices[i]);
        }
        return notGP;
    }

3.2 解法二:动态规划

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        int buy1 = -prices[0], sell1 = 0;
        int buy2 = -prices[0], sell2 = 0;
        for (int i=1; i<n; i++) {
            buy1 = Math.max(buy1, -prices[i]);
            sell1 = Math.max(sell1, buy1+prices[i]);
            buy2 = Math.max(buy2, sell1-prices[i]);
            sell2 = Math.max(sell2, buy2+prices[i]);
        }
        return sell2;
    }

四、309. 最佳买卖股票时机含冷冻期

4.1 动态规划

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        int[][] dp = new int[n][3];
        // dp[i][0] 持有股票  
        // dp[i][1] 今天卖出后,处于冷冻期  
        // dp[i][2]  不持有股票,并且不处于冷冻期
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = 0;
        for (int i=1; i<n; i++) {
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][2]-prices[i]);
            dp[i][1] = dp[i-1][0] + prices[i];
            dp[i][2] = Math.max(dp[i-1][1], dp[i-1][2]);
        }
        return Math.max(dp[n-1][1], dp[n-1][2]);
    }

4.2 动态规划(空间优化)

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n<2) return 0;
        // 今天买入股票
        int hasGP = -prices[0];
        // 今天售出股票
        int sellGP = 0;
        // 今天不持有股票
        int notGP = 0;

        for (int i=1; i<n; i++) {
            int tempHasGP = hasGP;
            int tempSellGP = sellGP;
            hasGP = Math.max(hasGP, notGP-prices[i]);
            sellGP = tempHasGP + prices[i];
            notGP = Math.max(tempSellGP, notGP);
        }
        return Math.max(sellGP, notGP);
    }

五、188. 买卖股票的最佳时机 IV

5.1 动态规划:是123. 买卖股票的最佳时机 III 问题的扩展

    public int maxProfit(int k, int[] prices) {
        int n = prices.length;
        if (n<2 || k<1) return 0;
        // dp[i][0] 第i次买, dp[i][1] 第i次卖
        int[][] dp = new int[k][2];
        for (int j=0;j<k; j++) {
            dp[j][0] = -prices[0];
            dp[j][1] = 0;
        }
        for (int i=1; i<n; i++) {
            dp[0][0] = Math.max(dp[0][0], -prices[i]);
            dp[0][1] = Math.max(dp[0][1], dp[0][0]+prices[i]);
            for (int j=1; j<k; j++) {
                dp[j][0] = Math.max(dp[j-1][1]-prices[i], dp[j][0]);
                dp[j][1] = Math.max(dp[j][1], dp[j][0]+prices[i]);
            }
        }
        return dp[k-1][1];
    }

六、714. 买卖股票的最佳时机含手续费

6.1 动态规划

    public int maxProfit(int[] prices, int fee) {
        int n = prices.length;
        if (n<2) return 0;
        // dp[i][0] 不持有股票, dp[i][1] 持有股票
        int[][] dp = new int[n][2];
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        for (int i=1; i<n; i++) {
            dp[i][0] = Math.max(dp[i-1][1]+prices[i]-fee, dp[i-1][0]);
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]-prices[i]);
        }
        return Math.max(dp[n-1][0], dp[n-1][1]);
    }

6.2 动态规划(空间优化)

    public int maxProfit(int[] prices, int fee) {
        int n = prices.length;
        if (n<2) return 0;
        int hasGP = -prices[0];
        int notGP = 0;
        for (int i=1; i<n; i++) {
            int t = hasGP;
            hasGP = Math.max(hasGP, notGP-prices[i]);
            notGP = Math.max(notGP, t+prices[i]-fee);
        }
        return Math.max(hasGP, notGP);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值