Алгоритм для поиска высоких/низких чисел с максимальным сравнением 1.5n

Я уже подумывал об этом домашнем задании. Учитывая числовой массив размером n, создайте алгоритм, который будет находить высокие и низкие значения с максимальным сравнением 1.5n.

Моя первая попытка была

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]

}

Моя проблема заключается в том, что каждая итерация цикла имеет одну из трех возможностей:

  • найдено низкое значение - сделано 1 сравнение.
  • найдено высокое значение - сделано 2 сравнения.
  • не найдено - сделано 2 сравнения.

Таким образом, для всего обхода массива можно сделать максимум 2n сравнений, что далеко от максимальной потребности в 1,5,1 сравнениях.

Ответ 1

Начните с пар чисел и найдите локальные минимальные и максимальные значения (n/2 сравнения). Затем найдите глобальный максимум из n/2 локальных maxes (n/2 сравнения) и аналогично глобальный min из локальных mins (n ​​/2 сравнения). Всего сравнений: 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

Обратите внимание, что указанное решение изменяет массив. Альтернативное решение:

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

Я знаю, что это уже ответили, но на случай, если кто-то ищет другой способ подумать об этом. Этот ответ похож на Lester's, но может обрабатывать нечетные значения n без нарушения и будет по-прежнему проводить максимум 1.5n сравнений. Секрет в модуле.;)

В качестве побочного эффекта обеспечения того, чтобы мы поместили последнее значение в соответствующий подвой массив, второй элемент в данном листе будет сравниваться и помещаться дважды. Однако, поскольку мы не меняем исходный массив, и нас интересует только высокий и низкий набор, это не имеет особого значения.

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

Это тот же ответ, что и ElKamina, но поскольку я уже начал писать псевдокод, я думал, что закончу и опубликую его.

Идея состоит в том, чтобы сравнить пары значений (n/2 сравнения), чтобы получить массив с высокими значениями и массив с низкими значениями. С каждым из этих массивов мы снова сравниваем пары значений (сравнения 2 * n/2) для получения наивысших и наименьших значений соответственно.

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

Здесь псевдокод:

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]
}

Этот код не учитывает, что n не является четным, или исходный массив пуст.

Ответ 4

Это вопрос, который у меня был во время интервью, и я нашел ответ с небольшим намеком от интервьюера, который был "Как вы сравниваете два числа?" (это действительно помогло).

Вот объяснение:

Допустим, у меня есть 100 чисел (вы можете легко заменить его на n, но он лучше работает для примера, если n - четное число). Что я делаю, так это то, что я разделил его на 50 списков из 2-х чисел. Для каждой пары я делаю одно сравнение, и я сделан (что составляет 50 сравнений к настоящему времени), тогда мне просто нужно найти минимум минимумов (это 49 сравнений) и максимум максимумов (что также 49 сравнений), так что мы должны сделать сравнения 49 + 49 + 50 = 148. Мы закончили!

Примечание. Чтобы найти минимум, действуем следующим образом (в псевдокоде):

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

И мы находим это в (n-1) сравнениях. Код почти одинаковый для максимума.