3

I am trying to figure out a divide and conquer algorithm with O(nlogn) time to solve the following real world problem -

Suppose we have an array of stock prices. Come up with an algorithm that prints out an array with the max profit for every day i in the array.

So for example, if we had array A = [4,6,2,1], our days would represent each index, and our output would be an array with values [2,-4,-1,-1] with the last day being value -A[i].

I have figured out a brute force algorithm that -

   1.) Scans the array for max after A[i]
   2.) Subtracts A[i] with max, places value in A', iterates to next day
   3.) When max reaches itself, repeat steps 1 & 2
   4.) When you reach the end, the value is -A[i], return

Also, I am confused if the time complexity of the algorithm described above would be o(n), or o(n^2). The biggest cost in the algorithm is finding the max, everything else is o(1).

Can someone please help me? Thanks

  • 1
    You can do this in linear time. Try to get all the information you need in one reverse pass over the array. – user2357112 May 03 '16 at 21:52
  • I don't understand, start from the end, and keep subtracting values to find each max profit, for each specific day? –  May 03 '16 at 21:53

2 Answers2

1

You don't want divide an conquer here. You can do this in linear time (O(n)). Here is the code in java, but you can do this in any language:

int[] maxProfit = new int[prices.length];
int maxPrice = 0;
for (int i = prices.length - 1; i >= 0; i--) {
 maxProfit[i] = maxPrice - prices[i];
 maxPrice = Math.max(maxPrice, prices[i]);
}

This assumes you have an array, prices, which contains your prices as integers.

The key here is that you can get all the information you need by starting from the end and going backward.

nhouser9
  • 6,730
  • 3
  • 21
  • 42
  • Ah, I see. Since it is a single pass through the array, the time complexity would be a simple o(n). However, I still am analyzing the different time complexities of this simple problem, and am lost on the o(logn). I understand it is not as efficient as this algorithm. However, I am confused on how you would find the best in each different case of partitioning the array, and inserting it into an array, –  May 03 '16 at 22:08
  • @tarfar A divide and conquer solution doesn't work well here. The fact is that for each element, we have to look at each element after it. So even if we somehow 'divide' the array, we will still have to look at the other division to determine our result. – nhouser9 May 03 '16 at 22:26
  • yeah I understand, I am just curious as to how it works though. The O(n) algorithm is amazingly quick, however, I am analyzing divide and conquer algorithms, and applying them to different problems to try and understand the concept a little better. So when we divide each half, we would have to compare it with the other half? –  May 03 '16 at 22:31
0

This can be done in one linear scan so complexity is O(n). First of all lets create maximums array M i.e. M[i] contains maximum number we have after i-th day.

By reverse linear scan it is easy to do:

We have A = [4,6,2,1], so in a first step we are taking last element of A which is 1 and it which is maximum value at the moment, so M[3] = 1, then we get M[2] = max(M[3],A[2]) = 2, then we get M[1] = max(M[2],A[1]) = 6, finally in the last step we get M[0] = max(M[1], A[0]) = 6.

We will have M = [6,6,2,1]. This algorithm has O(n) complexity, then we will run one more loop to identify maximum profit for each day, which is also has O(n) complexity. BTW we can omit storing values of M and instead of storing whole array to store only maximum value after i-th day.

simon
  • 1,405
  • 1
  • 15
  • 24
  • Thank you for your answer, however, shouldn't M be [2,-4,-1,-1]? I am trying to find the maximum profit of selling at every day in the array –  May 03 '16 at 22:10
  • @tarfar sorry for confusion, M[i] is a max(A[i], A[i+1],...,A[A.length-1]). Maximum profit P will be equal to P[i] = M[i+1]-A[i] in this case P=[6-4, 2-6, 1-2, 0-1] = [2, -4, -1 ,-1]. – simon May 03 '16 at 22:14
  • no problem, I got confused there for a second. Do you have ideas on how to transform this into o(nlogn)? I know we can split the array in three different parts, recursively looking through L, R, and both of them. –  May 03 '16 at 22:16
  • Also, would a proof by induction be the best way to prove this time complexity? –  May 03 '16 at 22:34
  • O(n) is faster than O(nlogn), however lets use divide and conquer. Let suppose we solved the problem for AL=[4,6] and AR=[2,1]. Solutions are SL = [2,-6] and SR=[-1,-1]. We have to concat SL and SR to get answer to A=[4,6,2,1] problem. For this we will not touch anything in AR and only for the AL[i] item we should consider maximum number coming after AL[i] and max number of AR array, so for AL[0] we will get max is 6 and it is in AL so we will not touch it, for AL[1] the max 2 and it is in the AR array and we have to adjust it and we will get SL_adjusted[1] = -6+2 = -4. => S=[2,-4,-1,-1] – simon May 03 '16 at 22:38
  • @tarfar this is not a good problem for using divide and conquer technique. If you want to learn and practice this method the merge sort is the best case which can illustrate the method. – simon May 03 '16 at 22:42
  • regarding time complexity: It is better to use Master theorem for proving the complexity O(nlogn) when using divide and conquer method. As you see we divided array into 2 equal arrays and then for combining a result did a linear work, so T(n) = 2T(n/2)+cn. From Master theorem we will get T(n) = O(nlogn) – simon May 03 '16 at 22:49
  • I am confused on how you got the max of 6 & 2. I got completely lost at that part –  May 03 '16 at 22:57
  • Master Theorem is great for recurrences, I agree, what about O(n) algorithms? –  May 03 '16 at 22:58
  • Regarding max when you solving problem for A=[4,6,2,1] for 2nd day you should check maximum in 3rd and 4th days which is 2, when you solving 2 problems for AL and AR after solving you should adjust left array and seek for maximum in right array as well, that is how I get 2 for AL[1]. Regarding O(n) complexity proving. You are doing one (or any fixed number) linear scan i.e. n iteration and for each iteration you are doing less then some number c elementary operations, hence total you are doing less then c*n elementary operations which is by definition is O(n) complexity. – simon May 03 '16 at 23:07
  • Ah, I see. So once you have the solution in the left and right halves, you compare the original value of A[i] with max if it is not in the same sub array, and then adjust it to the correct value, and pace in our profit array? –  May 03 '16 at 23:21
  • So, are we not breaking down the array any further from the Right and Left half, we did at the very beginning? –  May 03 '16 at 23:23
  • @tarfar Right, the only optimization we can do is only to look for adjustments only in left array, since for right array the profit will not depend on previous days. Sure we are braking down arrays further with recursion until will get 1 element arrays. – simon May 03 '16 at 23:25
  • 1
    Wow, you have been so helpful! Thank you so much! I definitely understand this so much better with all of your help. –  May 03 '16 at 23:38