LeetCode——买卖股票的最佳时机

股票买卖分析:(引用自《labuladong的算法》)


这个解释应该很清楚了,如果 buy,就要从利润中减去 prices[i],如果 sell,就要给利润增加 prices[i]。今天的最⼤利润就是这两种可能选择中较⼤的那个。⽽且注意 k 的限制,我们在选择 buy 的时候,把 k 减⼩了 1,很好理解吧,当然你也可以在 sell 的时候减 1,⼀样的。
还差最后⼀点点,就是定义 base case,即最简单的情况。

Q:假设你有一个数组,其中第i个元素是某只股票在第i天的价格。
如果你最多只能完成一笔交易(即买一股和卖一股股票),设计一个算法来求最大利润。
A:(自己做的)当前值比最小值小,代替最小值;当前值比最小值大,计算差值,和之前的差值做判断。

    public int maxProfit(int[] prices) {
        if (prices.length == 0)
            return 0;
        int sum = 0;
        int min = prices[0];
        for (int i = 1; i < prices.length; i++) {
            if (min < prices[i])
                sum = Math.max(sum, prices[i] - min);
            else if (min > prices[i])
                min = prices[i];
        }
        return sum;
    }

用统一方法做:

    public int maxProfit(int[] prices) {
        if (prices.length == 0)
            return 0;
        int n = prices.length;
        int[][] dp = new int[n][2];
        dp[0][0] = 0;//= max(0, -infinity + prices[i]) = 0
        dp[0][1] = -prices[0];//=max(-infinity, 0 - prices[i])
        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], -prices[i]);
        }
        return dp[n - 1][0];
    }

Q:假设你有一个数组,其中第i个元素表示某只股票在第i天的价格。
设计一个算法来寻找最大的利润。你可以完成任意数量的交易(例如,多次购买和出售股票的一股)。但是,你不能同时进行多个交易(即,你必须在再次购买之前卖出之前买的股票)。
A:(自己做)所有的涨坡的最高点减最低点

    public static int maxProfit(int[] prices) {
        if (prices.length <= 1)
            return 0;
        int min = prices[0];
        int sum = 0;
        for (int i = 1; i < prices.length; i++) {
            if (prices[i] < min)
                min = prices[i];
            if (prices[i] > min && (i == prices.length - 1 || prices[i] >= prices[i + 1])) {
                sum += (prices[i] - min);
                min = prices[i];
            }
        }
        return sum;
    }

实际上可以相当于进行无数次买卖。

    public int maxProfit_inf(int[] prices) {
        int n = prices.length;
        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];
    }

Q:假设你有一个数组,其中第i个元素是某只股票在第i天的价格。
设计一个算法来求最大的利润。你最多可以进行两次交易。
注意:
你不能同时进行多个交易(即,你必须在再次购买之前出售之前买的股票)。
A:(自己做)结合一下前两个代码,在每个峰值计算一次前后两个子数组的最大利润,相加比较。

    public static int maxProfit(int[] prices) {
        if (prices.length <= 1)
            return 0;
        int min = prices[0];
        int sum = 0;
        for (int i = 1; i < prices.length; i++) {
            if (prices[i] < min)
                min = prices[i];
            //找到峰值的时候
            if (prices[i] > min && (i == prices.length - 1 || prices[i] >= prices[i + 1])) {
                int left = max(Arrays.copyOfRange(prices, 0, i + 1));
                int right = 0;
                if (i != prices.length - 1) {
                    right = max(Arrays.copyOfRange(prices, i + 1, prices.length));
                }
                sum = Math.max(sum, (left + right));
                min = prices[i];
            }
        }
        return sum;
    }

    public static int max(int[] prices) {
        if (prices.length == 0)
            return 0;
        int sum = 0;
        int min = prices[0];
        for (int i = 1; i < prices.length; i++) {
            if (min < prices[i])
                sum = Math.max(sum, prices[i] - min);
            else if (min > prices[i])
                min = prices[i];
        }
        return sum;
    }

或者下面k次的方法把k改为2.

Q:假设你有一个数组,其中第i个元素是某只股票在第i天的价格。
设计一个算法来求最大的利润。你最多可以进行k次交易。
注意:
你不能同时进行多个交易(即,你必须在再次购买之前出售之前买的股票)。
A:⼀次交易由买⼊和卖出构成,⾄少需要两天。所以说有效的限制 k 应该不超过 n/2,如果超过,就没有约束作⽤了,相当于 k = +infinity

    public int maxProfit(int k, int[] prices) {
        if (k < 1 || prices.length == 0)
            return 0;
        int n = prices.length;
        if (k > n / 2) {//相当于k = +infinity
            return maxProfit_inf(prices);
        }
        int[][][] dp = new int[n][k + 1][2];
        for (int i = 0; i < n; i++) {
            for (int j = k; j >= 1; j--) {
                if (i == 0) {
                    dp[i][j][0] = 0;
                    dp[i][j][1] = -prices[0];
                } else {
                    dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
                    dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
                }
            }
        }
        return dp[n - 1][k][0];
    }

    private int maxProfit_inf(int[] prices) {
        int n = prices.length;
        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];
    }

Q:给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
A:第 i 天选择 buy 的时候,要从 i-2 的状态转移,⽽不是 i-1 。

    public int maxProfit_inf(int[] prices) {
        if(prices.length == 0)
            return 0;
        int n = prices.length;
        int[][] dp = new int[n][2];
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        for (int i = 1; i < n; i++) {
            if(i==1){
                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]);
                continue;
            }
            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 - 2][0] - prices[i]);//选择 buy 的时候,要从 i-2 的状态转移
        }
        return dp[n - 1][0];
    }

Q:给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。你可以无限次地完成交易,但是你每次交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。返回获得利润的最大值。

示例 1:
输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
输出: 8
解释: 能够达到的最大利润:
在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

注意:
0 < prices.length <= 50000.
0 < prices[i] < 50000.
0 <= fee < 50000.

A:每次交易要⽀付⼿续费,只要把⼿续费从利润中减去即可。

    public int maxProfit_inf(int[] prices, int fee) {
        if(prices.length == 0)
            return 0;
        int n = prices.length;
        int[][] dp = new int[n][2];
        dp[0][0] = 0;
        dp[0][1] = -prices[0] - fee;
        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] - fee);//在第⼀个式⼦⾥减也是⼀样的,相当于卖出股票的价格减⼩了。
        }
        return dp[n - 1][0];
    }
原文地址:https://www.cnblogs.com/xym4869/p/12499592.html