【问题标题】:Buy and Sell stocks twice买卖股票两次
【发布时间】:2017-09-26 21:23:54
【问题描述】:

我正在努力理解这个problem,我需要在最多允许两次买卖股票时找出最大利润。提供的解决方案讨论了从左到右维护价格差异数组,这对我来说很有意义。但是,该帖子还谈到了从右到左保持另一个价格差异数组,我无法理解这种逻辑,为什么在第一次交易后会产生利润。

Prices= [1, 4, 5, 7, 6, 3, 2, 9]
left  = [0, 3, 4, 6, 6, 6, 6, 8]
right = [8, 7, 7, 7, 7, 7, 7, 0]
max_profit = 13

【问题讨论】:

    标签: algorithm language-agnostic dynamic-programming


    【解决方案1】:

    您提到的建议解决方案中有两个数组的事实与仅允许使用 2 个事务的问题的约束有关。

    正如还指定的,交易不应该被插入——一个交易应该在另一个交易之前(在左边)(在右边)。

    更具体地说,提议的解决方案中的两个数组表示以下内容:

    • left[i] = 在区间 [0, i] 内可以通过买卖进行的最佳交易。如果在时间 j 完成卖出(j 在 [0, i] 中),则应以从 0 到 j 的最低价格进行买入。

    • right[i] = 在区间 [i, n-1] 内可以通过买卖进行的最佳交易。如果在时间 j 买入(其中 j 在 [i, n-1] 中),则应以 j 到 n-1 的最高价格卖出。

    所有需要找到的只是两个事务的一个很好的分离点i。那么最佳组合将涉及利润 left[i] + right[i],这可以通过尝试所有可能的 i 值来找到。

    【讨论】:

    • 那么最好的组合就是利润 left[i] + right[i],不应该是left[i - 1] + right[i],因为我们结合了前一天和当天卖出的最大利润?
    • @Brayoni 这是一个很好的观点。请注意,通过使用 left[i] + right[i] 而不是更干净的 left[i - 1] + right[i] 只会有风险考虑显然无效的解决方案,即我们在购买第二只股票时出售第一只股票一。但是这种情况实际上并不是无效的,因为它实际上等同于执行单个事务。声明中提到我们可以最多使用两个事务(即单个事务也是有效的),这就是为什么使用 left[i] + right[i] 的官方解决方案也可以正常工作的原因.
    【解决方案2】:

    你可以用DP来解决这个问题,首先设置你不买卖股票的情况,所以第一个利润为零,按照相同的顺序获利

    仅进行一笔交易时

    跟踪数组并保持之前价格的最小值,最大利润为数组中的最大值 - 最小值。所以问题基本上是在数组中找到最大值和最小值,差异将是最大利润,这里我们只是更新利润数组,以了解在特定日期进行交易之前的最大利润是多少。该数组将用作询问进一步事务中的数据使用情况。

    // Condition for the only one transaction is possible
           for (int i = 1; i < n; i++) {
             min = Math.min(price[i - 1], min);
               profit[i] = Math.max(profit[i - 1], price[i] - min);
            }
    

    如果最多可以进行两次交易

    现在事情变得很棘手,我们必须跟踪之前为获得最大利润所做的任何计算,直到 k-1 交易(这里 k=2)。对于任意数量的事务,该问题都可以成为动态问题。

    profit for a particular day is = max{ if no transaction is made (Then previous max profit, ie profit[i - 1]),
    previous_profit + Max of sale possible{present price - all previous price(i,i-1,...0)) 
    

    对于 k=2

    //   Condition for at most two transaction is possible
            for (int i = 1; i < n; i++) {
               max = Math.max(max, profit[i] - price[i]);
                 profit[i] = Math.max(profit[i - 1], max + price[i]);
            }
    

    这是 k 笔交易的通用代码 我们只需要两个数组来跟踪之前的利润值并在每次迭代中覆盖。也可以使用二维数组完成,但我们不需要任何以前的数据,所以我用偶数和正数据数组制作了它

       package DynamicProblems;
    
        public class StockSales {
    
            private static int maxProfit(int price[], int n, int k) {
                int currentProfit[] = new int[n];
                int previousProfit[];
                int evenProfit[] = new int[n];
                int oddProfit[] = new int[n];
    
                for (int t = 0; t <= k - 1; t++) {
                    int max = Integer.MIN_VALUE;
                    if (t % 2 == 1) {
                        currentProfit = oddProfit;
                        previousProfit = evenProfit;
                    } else {
                        currentProfit = evenProfit;
                        previousProfit = oddProfit;
                    }
    
                    for (int i = 1; i < n; i++) {
                        max = Math.max(max, previousProfit[i - 1] - price[i - 1]);
                        currentProfit[i] = Math.max(currentProfit[i - 1], max + price[i]);
                    }
                }
                return currentProfit[n - 1];
            }
    
            public static void main(String args[]) {
                int price[] = {3, 4, 10, 103};
                int k = 1;
                int n = price.length;
                System.out.println("\nMaximum Profit = " + maxProfit(price, n, k));
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      • 2018-03-20
      • 2021-11-29
      • 2015-09-21
      相关资源
      最近更新 更多