Algorithm to find high/low numbers with at most 1.

2019-03-15 09:58发布

问题:

I've been thinking about this homework question for a bit now. Given an number array of size n, design an algorithm that will find the high and and low values with at most 1.5n comparisons.

My first try was

int high=0
int low= Number.MaxValue //problem statement is unclear on what type of number to use
Number numList[0 . . n] //number array, assuming unsorted

for (i=0, i < n, i++) {
  if (numList[i] > high)
    high = numList[i]

  else if (numList[i] < low)
    low = numList[i]

}

My problem is each iteration of the loop has one of three possibilities:

  • low value is found - 1 comparison made
  • high value is found - 2 comparisons made
  • neither is found - 2 comparisons made

So for an entire array traversal, a maximum of 2n comparisons can be made, which is a far cry from the problem maximum requirement of 1.5n comparisons.

回答1:

Start with a pairs of numbers and find local min and max (n/2 comparisons). Next, find global max from n/2 local maxes (n/2 comparisons), and similarly global min from local mins (n/2 comparisons). Total comparisons: 3*n/2 !

For i in 0 to n/2: #n/2 comparisons
    if x[2*i]>x[2*i+1]:
        swap(x,2*i,2*i+1)

global_min = min( x[0], x[2], ...) # n/2 comparisons
global_max = max( x[1], x[3], ...) # n/2 comparisons

Note that the above solution changes the array. Alternate solution:

Initialize min and max
For i = 0 to n/2:
    if x[2*i]<x[2*i+1]:
        if x[2*i]< min:
            min = x[2*i]
        if x[2*i+1]> max:
            max = x[2*i+1]
    else:
        if x[2*i+1]< min:
            min = x[2*i+1]
        if x[2*i]> max:
            max = x[2*i]


回答2:

I know this has already been answered, but in case someone is looking for another way to think about this. This answer is similar to Lester's, but can handle odd values of n without breaking and will still make at most 1.5n comparisons. The secret is in the modulus. ;)

As a side effect of ensuring we place the last value in the proper sub array, the second element in the givenList will be compared and placed twice. However, since we are not changing the original array and we are only interested in the high and low of the set, this does not really make a difference.

Initialize lowArray and highArray
Initialize subArrayCounter to 0

For i = 0; i < n; i+=2
    X = givenList[i];
    Y = givenList[(i+1)%n];
    If(x < y)
        lowArray[subArrayCounter] = x;
        highArray[subArrayCounter] = y;
        subArrayCounter++;
    else
        lowArray[subArrayCounter] = y;
        highArray[subArrayCounter] = x;
        subArrayCounter++;

Initialize low to lowArray[0];
Initialize high to highArray[0];

For i = 1; i < lowArray.length; i++
    If(lowArray[i] < low)
        Low = lowArray[i];

For i = 1; i < highArray.length; i++
    If(highArray[i] > high)
        High = highArray[i]


回答3:

This is the same answer as ElKamina but as I had already started writing the pseudo code I thought I'd finish and post it.

The idea is to compare pairs of values (n/2 comparisons) to get an array of high values and an array of low values. With each of those arrays we again compare pairs of values (2 * n/2 comparisons) to get the highest and lowest values respectively.

n/2 + 2*n/2 = 1.5n comparisons

Here's the pseudocode:

int[] highNumList;
int[] lowNumList;

for (i = 0, i < n, i+=2)
{
    a = numList[i];
    b = numList[i+1];
    if (a > b)
    {
        highNumList.Add(a);
        lowNumlist.Add(b);
    }
    else
    {
        highNumlist.Add(b);
        lowNumList.Add(a);
    }
}

int high = highNumList[0];
int low = lowNumList[0];

for (i = 0, i < n/2, i+=2)
{
    if (highNumList[i] < highNumList[i+1])
        high = highNumList[i+1]
    if (lowNumList[i] > lowNumList[i+1])
        low = lowNumList[i+1]
}

This code doesn't account for n not being even or the initial array being empty.



回答4:

This is a question I had during an interview and I found the answer with a small hint from the interviewer which was "How do you compare two numbers?" (it really helped).

Here is the explanation:

Lets say I have 100 numbers (you can easily replace it by n but it work better for the example if n is an even number). What I do is that I split it into 50 lists of 2 numbers. For each couple I make one comparison and I'm done (which makes 50 comparisons by now) then I just have to find the minimum of the minimums (which is 49 comparisons) and the maximum of the maximums (which is 49 comparisons as well) such that we have to make 49+49+50=148 comparisons. We're done !

Remark: to find the minimum we proceed as follow (in pseudo code):

    n=myList.size();
    min=myList[0];
    for (int i(1);i<n-1;i++)
    {
    if (min>myList[i]) min=myList[i];
    }
    return min;

And we find it in (n-1) comparisons. The code is almost the same for maximum.