Найти второй по величине элемент в массиве с минимальным количеством сравнений - PullRequest
65 голосов
/ 02 сентября 2010

Какое количество требуемых сравнений для массива размера N?

Ответы [ 24 ]

110 голосов
/ 02 сентября 2010

Оптимальный алгоритм использует n + log n-2 сравнений. Думайте об элементах как о конкурентах, и турнир оценивает их.

Сначала сравните элементы, как в дереве

   |
  / \
 |   |
/ \ / \
x x x x

это требует n-1 сравнений, и каждый элемент участвует в сравнении не более log n раз. Вы найдете самый большой элемент как победитель.

Второй по величине элемент, должно быть, проиграл матч победителю (он не может проиграть матч другому элементу), поэтому он является одним из log n элементов, с которыми играл победитель. Вы можете найти, какие из них, используя log n - 1 сравнений.

Оптимальность доказывается аргументом противника. См. https://math.stackexchange.com/questions/1601 или http://compgeom.cs.uiuc.edu/~jeffe/teaching/497/02-selection.pdf или http://www.imada.sdu.dk/~jbj/DM19/lb06.pdf или https://www.utdallas.edu/~chandra/documents/6363/lbd.pdf

12 голосов
/ 02 сентября 2010

Вы можете найти второе по величине значение с не более чем 2 · ( N -1) сравнениями и двумя переменными, которые содержат наибольшее и второе по величине значение:

largest := numbers[0];
secondLargest := null
for i=1 to numbers.length-1 do
    number := numbers[i];
    if number > largest then
        secondLargest := largest;
        largest := number;
    else
        if number > secondLargest then
            secondLargest := number;
        end;
    end;
end;
9 голосов
/ 07 августа 2013

Используйте алгоритм Bubble sort или Selection sort, который сортирует массив в порядке убывания.Не сортируйте массив полностью.Всего два прохода.Первый проход дает самый большой элемент, а второй проход дает второй по величине элемент.

Нет.сравнений для первого прохода: n-1

Нет.сравнений для первого прохода: n-2

Всего нет.сравнения для поиска второго по величине: 2n-3

Может быть, вы можете обобщить этот алгоритм.Если вам нужен третий по величине, то вы делаете 3 прохода.

В соответствии с вышеприведенной стратегией вам не нужны никакие временные переменные, так как сортировка по пузырям и сортировка по выбору - это , сортировка по месту алгоритмы.

2 голосов
/ 02 сентября 2010

Вот код, который может быть неоптимальным, но, по крайней мере, фактически находит второй по величине элемент:

if( val[ 0 ] > val[ 1 ] )
{
    largest = val[ 0 ]
    secondLargest = val[ 1 ];
}
else
{
    largest = val[ 1 ]
    secondLargest = val[ 0 ];
}

for( i = 2; i < N; ++i )
{
    if( val[ i ] > secondLargest )
    {
        if( val[ i ] > largest )
        {
            secondLargest = largest;
            largest = val[ i ];
        }
        else
        {
            secondLargest = val[ i ];
        }
    }
}

Требуется как минимум N-1 сравнений, если самые большие 2 элемента находятся в начале массива и не более 2N-3 в худшем случае (один из первых 2 элементов является самым маленьким в массиве).

1 голос
/ 22 апреля 2011

дело 1 -> 9 8 7 6 5 4 3 2 1
дело 2 -> 50 10 8 25 ........
дело 3 -> 50 50 10 8 25 .........
дело 4 -> 50 50 10 8 50 25 .......

public void second element()  
{
      int a[10],i,max1,max2;  
      max1=a[0],max2=a[1];  
      for(i=1;i<a.length();i++)  
      {  
         if(a[i]>max1)  
          {
             max2=max1;  
             max1=a[i];  
          }  
         else if(a[i]>max2 &&a[i]!=max1)  
           max2=a[i];  
         else if(max1==max2)  
           max2=a[i];  
      }  
}
1 голос
/ 25 августа 2013

Я знаю, что это старый вопрос, но вот моя попытка решить его, используя алгоритм турнира.Это похоже на решение, используемое @sdcvvc, но я использую двумерный массив для хранения элементов.

Чтобы все работало, есть два предположения:
1) количество элементов в массивеявляется степенью 2
2) в массиве нет дубликатов

Весь процесс состоит из двух этапов:
1. построение двумерного массива путем сравнения двух на два элемента.Первая строка в 2D-массиве будет представлять собой весь входной массив.Следующая строка содержит результаты сравнений предыдущей строки.Мы продолжаем сравнение на вновь построенном массиве и продолжаем строить 2D-массив, пока не будет достигнут массив только из одного элемента (самый большой).
2. у нас есть 2D-массив, где последняя строка содержит только один элемент: самый большойодин.Мы продолжаем идти снизу вверх, в каждом массиве находим элемент, который был «побит» наибольшим, и сравниваем его с текущим «вторым по величине» значением.Чтобы найти элемент, побитый наибольшим, и чтобы избежать O (n) сравнений, мы должны сохранить индекс самого большого элемента в предыдущей строке.Таким образом, мы можем легко проверить соседние элементы.На любом уровне (выше корневого уровня) соседние элементы получаются как:

leftAdjacent = rootIndex*2
rightAdjacent = rootIndex*2+1,

, где rootIndex - это индекс самого большого (корневого) элемента на предыдущем уровне.

Я знаюВопрос требует C ++, но вот моя попытка решить его в Java.(Я использовал списки вместо массивов, чтобы избежать беспорядочного изменения размера массива и / или ненужных вычислений размера массива)

public static Integer findSecondLargest(List<Integer> list) {
        if (list == null) {
            return null;
        }
        if (list.size() == 1) {
            return list.get(0);
        }
        List<List<Integer>> structure = buildUpStructure(list);
        System.out.println(structure);
        return secondLargest(structure);

    }

    public static List<List<Integer>> buildUpStructure(List<Integer> list) {
        List<List<Integer>> newList = new ArrayList<List<Integer>>();
        List<Integer> tmpList = new ArrayList<Integer>(list);
        newList.add(tmpList);
        int n = list.size();
        while (n>1) {
            tmpList = new ArrayList<Integer>();
            for (int i = 0; i<n; i=i+2) {
                Integer i1 = list.get(i);
                Integer i2 = list.get(i+1);
                tmpList.add(Math.max(i1, i2));
            }
            n/= 2;
            newList.add(tmpList);   
            list = tmpList;
        }
        return newList;
    }

    public static Integer secondLargest(List<List<Integer>> structure) {
        int n = structure.size();
        int rootIndex = 0;
        Integer largest = structure.get(n-1).get(rootIndex);
        List<Integer> tmpList = structure.get(n-2);
        Integer secondLargest = Integer.MIN_VALUE;
        Integer leftAdjacent = -1;
        Integer rightAdjacent = -1;
        for (int i = n-2; i>=0; i--) {
            rootIndex*=2;
            tmpList = structure.get(i);
            leftAdjacent = tmpList.get(rootIndex);
            rightAdjacent = tmpList.get(rootIndex+1); 
            if (leftAdjacent.equals(largest)) {
                if (rightAdjacent > secondLargest) {
                    secondLargest = rightAdjacent;
                }
            }
            if (rightAdjacent.equals(largest)) {
                if (leftAdjacent > secondLargest) {
                    secondLargest = leftAdjacent;
                }
                rootIndex=rootIndex+1;
            }
        }

        return secondLargest;
    }
1 голос
/ 27 июля 2017

PHP версия алгоритма Гамбо: http://sandbox.onlinephpfunctions.com/code/51e1b05dac2e648fd13e0b60f44a2abe1e4a8689

$numbers = [10, 9, 2, 3, 4, 5, 6, 7];

$largest = $numbers[0];
$secondLargest = null;
for ($i=1; $i < count($numbers); $i++) {
    $number = $numbers[$i];
    if ($number > $largest) {
        $secondLargest = $largest;
        $largest = $number;
    } else if ($number > $secondLargest) {
        $secondLargest = $number;
    }
}

echo "largest=$largest, secondLargest=$secondLargest";
1 голос
/ 15 мая 2013

Извините, код JS ...

Протестировано с двумя входами:

a = [55,11,66,77,72];
a = [ 0, 12, 13, 4, 5, 32, 8 ];

var first = Number.MIN_VALUE;
var second = Number.MIN_VALUE;
for (var i = -1, len = a.length; ++i < len;) {
    var dist = a[i];
    // get the largest 2
    if (dist > first) {
        second = first;
        first = dist;
    } else if (dist > second) { // && dist < first) { // this is actually not needed, I believe
        second = dist;
    }
}

console.log('largest, second largest',first,second);
largest, second largest 32 13

Это должно иметь максимум a.length * 2 сравнения и проходит список только один раз.

1 голос
/ 11 июля 2017

Предположим, что предоставленный массив является inPutArray = [1,2,5,8,7,3] ожидаемый O / P -> 7 (второй по величине)

 take temp array 
      temp = [0,0], int dummmy=0;
    for (no in inPutArray) {
    if(temp[1]<no)
     temp[1] = no
     if(temp[0]<temp[1]){
    dummmy = temp[0]
    temp[0] = temp[1]
    temp[1] = temp
      }
    }

    print("Second largest no is %d",temp[1])
0 голосов
/ 05 ноября 2017
class solution:
def SecondLargestNumber (self,l):
    Largest = 0
    secondLargest = 0
    for i in l:
        if i> Largest:
            secondLargest = Largest
        Largest = max(Largest, i)
    return Largest, secondLargest
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...