简体   繁体   English

买卖股票,时间复杂度为O(n log n)

[英]Buy and Sell Stock, with O( n log n ) time complexity

EDIT: 编辑:
I appreciate the help from both of you but I have to stay with the bound of O( n log n ) time completicty and have to use the divide and conquer technique with binary recursion. 我感谢你们俩的帮助,但我必须遵守O(n log n)时间复杂性的界限,并且必须对二进制递归使用分治法。 I did not make that very clear in the initial posting 我在最初的帖子中没有说清楚

I have an unsorted array of ints where I have to buy stock on the ith day and sell it on the jth day for a maximum profit where the ith(the smaller value) day has to come before the jth(the larger value) day. 我有一些未分类的整数,我必须在第i天买入股票,然后在第j天卖出股票,以获取最大利润,而第i个(较小价值)日必须在第j个(较大价值)日之前。 So far i have found a solution that returns the purchase and sell days( index values of the array) and the max profit but it has a O(n^2) time complexity and I am having a hard time getting to the O(n log n) time complexity and implementing divide and conquer 到目前为止,我已经找到了一个返回购买和出售天数(数组的索引值)和最大利润的解决方案,但是它具有O(n ^ 2)的时间复杂度,而且我很难达到O(n log n)时间复杂度并实现分而治之

public static Profit BestProfit( int[] a, int i, int j )
{
   Profit bestProfit = new Profit();

   int n = j; 
   int maxProfit = 0;
   for(i = 0; i < n; i++)
   {
      for(j = i; j < n; j++)
      {
         if(a[j] - a[i] > maxProfit)
         {
            maxProfit = a[j] - a[i];
            bestProfit.setBuy( i );
            bestProfit.setSell( j );
            bestProfit.setMaxProfit( maxProfit );
         }
      }
   return bestProfit;
   } 

The params i is that start of the array and j in the end of the array The Profit class is a class that I created to hold buy, sell, and profit values. 参数i是数组的开始,j是数组的末尾。Profit类是我创建的用于保存购买,出售和利润值的类。

The three case that I have found that I need to account for are the largest profit for the first half of the array, largest profit for the second half of the array, and the case where the smallest value is on the 1st half of the array and the largest value is on the 2nd half of the array(I have already completed this part of the problem with a simple min/max function that solves the final case). 我发现需要考虑的三种情况是阵列前半部分的最大利润,阵列后半部分的最大利润,以及最小值在阵列第一部分的情况最大值在数组的第二个一半上(我已经用一个简单的最小/最大值函数来解决了最后的情况,完成了这一部分问题)。

I am stuck and any help with the divide and conquer implementation or tips of tricks would be greatly appreciated! 我被困住了,对分治法实施或技巧提示的任何帮助将不胜感激!

In O(n), pretty simple: 在O(n)中,非常简单:

public static Profit bestProfit(int[] a, int begin, int end) {
    Profit bestProfit = new Profit();
    int min = a[begin];
    int max = a[begin];
    int index = begin;
    int buy = 0;
    int sell = 0;
    int minIndex = begin;
    int maxIndex;
    int maxProfit = 0;
    for (int i = begin; i < end; i++) {
        int n = a[i];
        if (n < min) {
            minIndex = index;
            min = n;
            max = n;
        } else if (max < n) {
            max = n;
            maxIndex = index;
            if (maxProfit < (max - min)) {
                maxProfit = max - min;
                buy = minIndex;
                sell = maxIndex;
            }
        }
        index++;
    }
    bestProfit.setBuy(buy);
    bestProfit.setSell(sell);
    bestProfit.setMaxProfit(maxProfit);
    return bestProfit;
}

EDITED: with divide and conquer: 编辑:分而治之:

public static int divideAndConquer(int[] a, int i, int j, Profit profit, int min) {
    int minResult;
    if (i+1 >= j) {
        minResult = Math.min(a[i], min);
        if (a[i] - min > profit.getMaxProfit()) {
            profit.setBuy(min);
            profit.setSell(a[i]);
            profit.setMaxProfit(a[i] - min);
        }
    } else {
        int n = (j+i)/2;
        minResult = divideAndConquer(a, i, n, profit, min);
        minResult = divideAndConquer(a, n, j, profit, minResult);
    }
    return minResult;
}

public static void main(String[] args) {
    int[] prices = {20, 31, 5, 7, 3, 4, 5, 6, 4, 0, 8, 7, 7, 4, 1,10};
    Profit profit =new Profit();
    divideAndConquer(prices, 0, prices.length, profit, Integer.MAX_VALUE);
    System.out.println(profit);
}

You can improve it into O(n) with only three loops: 您可以通过三个循环将其改进为O(n):

  • First loop to build minimum arrays 第一个循环以构建最小数组
  • Second loop to build maximum arrays 第二个循环以建立最大数组
  • Third loop to find the maximum profit 第三循环寻找最大利润

More or less: 或多或少:

public static void main(String[] args) {

    int[] stockPrices = {2, 9, 5, 7, 3, 4, 5, 6, 4, 0, 8, 7, 7, 4, 1};

    int[] mins = new int[stockPrices.length - 1];
    int[] minsIndex = new int[stockPrices.length - 1];
    int[] maxs = new int[stockPrices.length - 1];
    int[] maxsIndex = new int[stockPrices.length - 1];

    int minIndex = -1;
    int min = Integer.MAX_VALUE;
    for (int i = 0; i < stockPrices.length - 1; i++) {
        if (stockPrices[i] < min) {
            min = stockPrices[i];
            minIndex = i;
        }
        mins[i] = min;
        minsIndex[i] = minIndex;
    }

    System.out.println("mins idx: " + Arrays.toString(minsIndex));
    System.out.println("mins: " + Arrays.toString(mins));

    int maxIndex = -1;
    int max = -1;
    for (int i = stockPrices.length - 1; i > 0; i--) {
        if (stockPrices[i] > max) {
            max = stockPrices[i];
            maxIndex = i;
        }
        maxs[i - 1] = max;
        maxsIndex[i - 1] = maxIndex;
    }

    System.out.println("maxs idx: " + Arrays.toString(maxsIndex));
    System.out.println("maxs: " + Arrays.toString(maxs));

    int maxProfit = -1;
    int buyIndex = -1;
    int sellIndex = -1;
    for (int i = 0; i < stockPrices.length - 1; i++) {
        int profit = maxs[i] - mins[i];
        if (profit > maxProfit) {
            maxProfit = profit;
            buyIndex = minsIndex[i];
            sellIndex = maxsIndex[i];
        }
    }

    System.out.println("buy at: " + buyIndex + " sell at: " + sellIndex + " profit: " + maxProfit);
}

Well, since you express the need of using divide and conquer, I will give another answer. 好吧,既然您表示需要使用分而治之,那么我将给出另一个答案。

Let say that the stock price is defined in an array: [p0, p1, ..., pn]. 假设股票价格是在数组中定义的:[p0,p1,...,pn]。

We can divide this problem into sub-problems into this definition. 我们可以将这个问题分为这个定义的子问题。

max profit = max(maxprofit([p0], [p1..pn]), maxprofit([p0..p1], [p2..pn]), ..., maxprofit([p0..pn-1], [pn]))

The first argument for maxprofit is the array of buying prices and the second one is the array of selling prices. maxprofit的第一个参数是购买价格的数组,第二个参数是销售价格的数组。

Look into the first sub-problem 研究第一个子问题

maxprofit([p0], [p1..pn])

We can divide this even more: 我们可以进一步划分:

maxprofit([p0], [p1..pn]) = max(maxprofit([p0], [p1]), maxprofit([p0],[p2..pn]))

We can solve max([p0], [p1]) since it's a base problem where profit = p1-p0. 我们可以解决max([p0], [p1])因为这是利润= p1-p0的基本问题。 Now we keep the result, and cache it. 现在我们保留结果,并将其缓存 Continue with breaking down maxprofit(([p0], [p2..pn]) and keep caching all the solution. 继续分解maxprofit(([p0], [p2..pn])并继续缓存所有解决方案。

Look into the second sub-problem 查看第二个子问题

This is the problem: 这就是问题:

maxprofit([p0..p1], [p2..pn])

Can be broken down into: 可以分为:

maxprofit([p0..p1], [p2..pn]) = max(maxprofit([p0], [p2..pn]), maxprofit([p1], [p2..pn]))

What's interesting: you don't have to break down maxprofit([p0], [p2..pn]) because you already have it in your cache when working on the first sub-problem. 有趣的是:您不必分解maxprofit([p0], [p2..pn])因为在处理第一个子问题时,您已经在缓存中拥有了它。 Therefore only the second sub-sub-problem need to be broken down. 因此,仅需要分解第二子问题。

I guess at this point you already get where this is going. 我想到此为止您已经知道了发展的方向。 Basically you need to keep breaking down the problem until you get into a base problem or if the problem is already cached. 基本上,您需要继续解决问题,直到遇到基本问题或问题已被缓存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM