zoukankan      html  css  js  c++  java
  • 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];
        }
    
  • 相关阅读:
    网页背景音乐
    CSS 实现背景半透明
    实战中总结出来的CSS常见问题及解决办法
    AsyncTask的简单使用
    ORMLiteDatabase的简单使用并且与其他的表相互联系
    传递消息--第三方开源--EventBus的简单使用
    通过messenger实现activity与service的相互通信
    通过Messenger与后台连接(单向操作,activity向service发送数据)
    怎么做QQ、微信等消息气泡
    通过bind实现activity与service的交互
  • 原文地址:https://www.cnblogs.com/xym4869/p/12499592.html
Copyright © 2011-2022 走看看