1

Lets say we have the following set of numbers representing values over time

1 2 3 10 1 20 40 60

Now I am looking for an algorithm to find the highest percentage increase from one time to another. In the above case, the answer would be the pair (1, 60), which has a 6000% increase.

So far, the best algorithm I can think of is a brute-force method. We consider all possible pairs using a series of iterations:

1st Iteration:

1-2 1-3 1-10 .. 1-60

2nd Iteration

 2-3 2-10 2-1 ... 2-60

(etc.)

This has complexity O(n3).

I've also been thinking about another approach. Find all the strictly increasing sequences, and determine only the perecentage increase in those strictly increasing sequences.

Does any other idea strike you guys? Please do correct me if my ideas are wrong!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Karthick
  • 2,844
  • 4
  • 34
  • 55
  • Can you clarify term 'Percentage Increase'? Is it `finalValue/initialValue`? – Nikita Rybak Feb 05 '11 at 01:01
  • Consider these numbers to be the production count of a company over a period of 8 years ( 2000 to 2008 ) , i.e, Production Count(2000) = 1, Production Count(2001) = 2 .. Production Count(2008) = 60; So the goal here is to find the time period which saw the highest increase in the production percentage, That could be from 2000 to 2001 or 2001 to 2003 or even 2000 to 2003! Do you need further clarifications? – Karthick Feb 05 '11 at 01:13
  • What are your limits? You can improve the time complexity to `O(n) ` if you allow the space complexity `O(n)` – Foo Bah Feb 05 '11 at 01:15
  • No limits... Only guarentee that I could give you would be that the values would be positive! – Karthick Feb 05 '11 at 01:15
  • There's a dynamic programming solution – Foo Bah Feb 05 '11 at 01:15
  • gr8 .. could you please explain me more? – Karthick Feb 05 '11 at 01:15
  • The brute force method has O(n^2) not n^3. – apadana Nov 15 '14 at 07:54

4 Answers4

2

I may have misunderstood the problem, but it seems that all you want is the largest and smallest numbers, since those are the two numbers that matter.

while true:
    indexOfMax = max(list)
    indexOfMin = min(list)
    list.remove(indexOfMax)
    list.remove(indexOfMin)
    if(indexOfmax < indexOfMin)
        contine
    else if(indexOfMax == indexOfMin)
        return -1
    else
        SUCCESS
Novikov
  • 4,399
  • 3
  • 28
  • 36
  • This is a wrong answer. Let's we have 10, 12, 8, 10, 5, 11. It is clear, that we have more than 50% increase between 5 and 11. But in your solution we throw out 5 and 12 in the very first iteration and will not find right answer. I think it will be helpful http://keithschwarz.com/interesting/code/?dir=single-sell-profit – Paval Oct 23 '15 at 07:17
0

As I understand (you didn't correct me in your comment), you want to maximize a[i]/a[j] for all j <= i. If that's correct, then for each i we only need to know smallest value before it.

int current_min = INFINITY;
double max_increase = 0;
for (int i = 0; i < n; ++i) {
    current_min = min(current_min, a[i]);
    max_increase = max(max_increase, a[i] / min);
}
Nikita Rybak
  • 67,365
  • 22
  • 157
  • 181
  • Ok.. lets assume it this way.. Plot this production count in a graph.. Now you could find peeks and the decreasing periods after the peek... So if Peek 1: 1-2 Peek2- 5-6.. So percetage increase in peek 1 is more than that in Peek 2.. got my point? – Karthick Feb 05 '11 at 01:26
  • 2
    @Karthick No. I have no idea what you're trying to do. – Nikita Rybak Feb 05 '11 at 01:29
0

So you just want to compare each number pair-wise and see which pair has the highest ratio from the second number to the first number? Just iterating with two loops (one with i=0 to n, and an inner loop with j=i+1 to n) is going to give you O(n^2). I guess this is actually your original solution, but you incorrectly said the complexity was O(n^3). It's n^2.

You could get to O(n log n), though. Take your list, make it into a list where each element is a pair of (index, value). Then sort it by the second element of the pair. Then have two pointers into the list, one coming from the left (0 to n-1), and the other coming from the right (n-1 to 0). Find the first pair of elements such that the left element's original index is less than the right element's original index. Done.

1 2 3 10 1 20 40 60
becomes
(1,0) (2,1) (3,2) (10,3) (1, 4) (20, 5) (40, 6) (60,7)
becomes
(1,0) (1,4) (2,1) (3,2) (10,3) (20,5) (40,6) (60,7)

So your answer is 60/1, from index 0 to index 7.

If this isn't what you're looking for, it would help if you said what the right answer was for your example numbers.

nsanch
  • 1
0

If I understand your problem correctly, you are looking for two indices (i, j) in the array with i < j that has the highest ratio A[j]/A[i]. If so, then you can reduce it to this related problem, which asks you to find the indices (i, j) with i ≤ j such that A[j] - A[i] is as large as possible. That problem has a very fast O(n)-time, O(1)-space algorithm that can be adapted to this problem as well. The intuition is to solve the problem for the array consisting of just the first element of your array, then for the first two elements, then the first three, etc. Once you've solved the problem for the first n elements of the array, you have an overall solution to the problem.

Let's think about how to do this. Initially, when you consider just the first element of the array, the best percentage increase you can get is 0% by comparing the element with itself. Now, suppose (inductively) that you've solved the problem for the first k array elements and want to see what happens when you look at the next array element. When this happens, one of two conditions holds. First, the maximum percentage increase over the first k elements might also be the maximum percentage increase over the first (k + 1) elements as well. For example, if the (k+1)st array element is an extremely small number, then chances are you can't get a large percentage increase from something in the first k elements to that value. Second, the maximum percentage increase might be from one of the first k elements to the (k + 1)st element. If this is the case, the highest percentage increase would be from the smallest of the first k elements to the (k + 1)st element.

Combining these two cases, we get that the best percentage increase over the first k + 1 elements is the maximum of

  • The highest percentage increase of the first k elements, or
  • The percentage increase from the smallest of the first k elements to the (k + 1)st element.

You can implement this by iterating across the array elements keeping track of two values - the minimum value you've seen so far and the pair that maximizes the percent increase. As an example, for your original example array of

1  2  3  10  1  20  40  60

The algorithm would work like this:

       1       2       3       10        1       20       40        60
min        1       1        1       1       1         1        1        1
best     (1,1)   (1, 2)  (1, 3)  (1, 10)  (1, 10)  (1, 20)   (1, 40)  (1, 60)

and you'd output (1, 60) as the highest percentage increase. On a different array, like this one:

3   1   4   2   5

then the algorithm would trace out like this: 3 1 4 2 5 min 3 1 1 1 1 best (3,3) (3,3) (1,4) (1,4) (1,5)

and you'd output (1, 5).

This whole algorithm uses only O(1) space and runs in O(n) time, which is an extremely good solution to the problem.

Alternatively, you can think about reducing this problem directly to the maximum single-sell profit problem by taking the logarithm of all of the values in your array. In that case, if you find a pair of values where log A[j] - log A[i] is maximized, this is equivalent (using properties of logarithms) to finding a pair of values where log (A[j] / A[i]) is maximized. Since the log function is monotonically increasing, this means that you have found a pair of values where A[j] / A[i] is maximized, as intended.

Community
  • 1
  • 1
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065