web-dev-qa-db-fra.com

Comment pouvons-nous trouver le deuxième maximum de array efficacement?

Est-il possible de trouver le deuxième nombre maximum à partir d'un tableau d'entiers en parcourant le tableau une seule fois?

Par exemple, j'ai un tableau de cinq entiers à partir duquel je veux trouver le deuxième nombre maximum. Voici une tentative que j'ai donnée dans l'interview:

#define MIN -1
int main()
{
    int max=MIN,second_max=MIN;
    int arr[6]={0,1,2,3,4,5};
    for(int i=0;i<5;i++){
        cout<<"::"<<arr[i];
    }
    for(int i=0;i<5;i++){
        if(arr[i]>max){
            second_max=max;
            max=arr[i];          
        }
    }
    cout<<endl<<"Second Max:"<<second_max;
    int i;
    cin>>i;
    return 0;
}

Cependant, l'intervieweur a mis au point le cas test int arr[6]={5,4,3,2,1,0};, qui l'empêche de passer à la condition if la deuxième fois. J'ai dit à l'intervieweur que le seul moyen serait d'analyser le tableau deux fois (deux boucles for). Quelqu'un a-t-il une meilleure solution?

18
Xinus

Votre initialisation de max et second_max à -1 est erronée. Et si le tableau a des valeurs comme {-2,-3,-4}?

Ce que vous pouvez faire à la place est de prendre les 2 premiers éléments du tableau (en supposant que le tableau ait au moins 2 éléments), de les comparer, d'assigner le plus petit à second_max et le plus grand à max:

if(arr[0] > arr[1]) {
 second_max = arr[1];
 max = arr[0];
} else {
 second_max = arr[0];
 max = arr[1];
}

Commencez ensuite la comparaison à partir du 3ème élément et mettez à jour max et/ou second_max selon vos besoins:

for(int i = 2; i < arr_len; i++){
    // use >= n not just > as max and second_max can hav same value. Ex:{1,2,3,3}   
    if(arr[i] >= max){  
        second_max=max;
        max=arr[i];          
    }
    else if(arr[i] > second_max){
        second_max=arr[i];
    }
}
28
codaddict

La solution la plus simple serait d’utiliser std::nth_element .

14
avakar

Vous avez besoin d'un deuxième test:

 for(int i=0;i<5;i++){  
   if(arr[i]>max){  
     second_max=max;  
     max=arr[i];            
   }
   else if (arr[i] > second_max && arr[i] != max){
     second_max = arr[i];
   }
 }
7
Anders Abel

Vous voilà:

std::pair<int, int> GetTwoBiggestNumbers(const std::vector<int>& array)
{
    std::pair<int, int> biggest;
    biggest.first = std::max(array[0], array[1]);  // Biggest of the first two.
    biggest.second = std::min(array[0], array[1]); // Smallest of the first two.

    // Continue with the third.
    for(std::vector<int>::const_iterator it = array.begin() + 2;
        it != array.end();
        ++it)
    {
        if(*it > biggest.first)
        {
            biggest.second = biggest.first;
            biggest.first = *it;
        }
        else if(*it > biggest.second)
        {
            biggest.second = *it;
        }
    }

    return biggest;
}
2
Johann Gerell

Votre code d'origine est correct, il vous suffit d'initialiser les variables max et second_max. Utilisez les deux premiers éléments du tableau.

2
Hans Passant

Une autre façon de résoudre ce problème consiste à utiliser des comparaisons entre les éléments. Comme par exemple,

a[10] = {1,2,3,4,5,6,7,8,9,10}

Comparez 1,2 et dites max = 2 et second max = 1

Maintenant, comparez 3 et 4 et comparez le plus grand d'entre eux avec max.

if element > max
     second max = max
     element = max
else if element > second max
     second max = element

L'avantage de ceci est que vous éliminez deux nombres en deux comparaisons seulement.

Faites le moi savoir, si vous avez du mal à comprendre cela.

1
Boolean

Étape 1. Décidez des deux premiers chiffres.
Étape 2. Parcourez les nombres restants.
Étape 3. Conservez le dernier maximum et le deuxième maximum.
Étape 4. Lorsque vous mettez à jour le deuxième maximum, sachez que vous ne faites pas le maximum et le deuxième maximum égaux.

Testé pour une entrée triée (ascendante et descendante), une entrée aléatoire, une entrée ayant des doublons, fonctionne bien.

#include <iostream>
#define MAX 50
int GetSecondMaximum(int* data, unsigned int size)
{
    int max, secmax;
    // Decide on first two numbers
    if (data[0] > data[1])
    {
        max = data[0];
        secmax = data[1];
    }
    else
    {
        secmax = data[0];
        max = data[1];
    }
    // Loop through remaining numbers
    for (unsigned int i = 2; i < size; ++i)
    {
        if (data[i] > max)
        {
            secmax = max;
            max = data[i];
        }
        else if (data[i] > secmax && data[i] != max/*removes duplicate problem*/)
            secmax = data[i];
    }
    return secmax;
}
int main()
{
    int data[MAX];
    // Fill with random integers
    for (unsigned int i = 0; i < MAX; ++i)
    {
        data[i] = Rand() % MAX;
        std::cout << "[" << data[i] << "] "; // Display input
    }
    std::cout << std::endl << std::endl;
    // Find second maximum
    int nSecondMax = GetSecondMaximum(data, MAX);
    // Display output
    std::cout << "Second Maximum = " << nSecondMax << std::endl;
    // Wait for user input
    std::cin.get();
    return 0;
}
1
Rajendra Uppal

Quickselect est la voie à suivre avec celui-ci. Le pseudo-code est disponible sur ce lien, je vais donc simplement expliquer l’algorithme général:

QuickSelect for kth largest number:
    Select a pivot element
    Split array around pivot
    If (k < new pivot index)
       perform quickselect on left hand sub array
     else if (k > new pivot index)
       perform quickselect on right hand sub array (make sure to offset k by size of lefthand array + 1)
     else
       return pivot

Ceci est bien évidemment basé sur le bon vieil algorithme quicksort.

En suivant cet algorithme, en sélectionnant toujours l’élément zéro comme pivot à chaque fois:

select 4th largest number:
1) array = {1, 3, 2, 7, 11, 0, -4}
partition with 1 as pivot
{0, -4, _1_, 3, 2, 7, 11}
4 > 2 (new pivot index) so...

2) Select 1st (4 - 3) largest number from right sub array
array = {3, 2, 7, 11}
partition with 3 as pivot
{2, _3_, 7, 11}
1 < 2 (new pivot index) so...

3) select 1st largest number from left sub array
array = {2}

4) Done, 4th largest number is 2

Cela laissera votre tableau dans un ordre indéfini par la suite, à vous de décider si c'est un problème.

1
Martin

Vérifiez cette solution.

max1 = a[0];
max2 = a[1];

for (i = 1; i < n; i++)
{
    if (max1 < a[i])
    {
        max2 = max1;
        max1 = a[i];
    }

    if (max2 == max1) max2 = a[i + 1];

    if (max2 == a[n])
    {
        printf("All numbers are the same no second max.\n");
        return 0;
    }

    if (max2 < a[i] && max1 != a[i]) max2 = a[i];
}
1
mitta

Ne pouvons-nous pas simplement trier cela par ordre décroissant et prendre le deuxième élément du tableau trié?

0
jhon
#include <iostream>
using namespace std;

int main() {

   int  max = 0;
    int sec_Max = 0;

    int array[] = {81,70,6,78,54,77,7,78};

    int loopcount = sizeof(array)/sizeof(int);

    for(int i = 0 ; i < loopcount ; ++i)
    {

        if(array[i]>max)
        {
            sec_Max = max;
            max = array[i];
        }

        if(array[i] > sec_Max && array[i] < max)
        {
            sec_Max = array[i];
        }
    }

    cout<<"Max:" << max << " Second Max: "<<sec_Max<<endl;

    return 0;
}
0
Bunny

Que diriez-vous de ce qui suit ci-dessous. make_heap is O(n) donc c'est efficace et c'est 1-pass. Nous trouvons le second max en prenant comme avantage qu'il doit s'agir de l'un des enfants de tas du parent, qui avait le maximum.

#include <algorithm>
#include <iostream>

int main()
{
    int arr[6]={0,1,2,3,4,5};

    std::make_heap(arr, arr+6);
    std::cout << "First Max: " << arr[0] << '\n';
    std::cout << "Second Max: " << std::max(arr[1], arr[2]) << '\n';
    return 0;
}
0
SJHowe

Voici quelque chose qui peut fonctionner,

public static int secondLargest(int[] a){
    int max=0;
    int secondMax=0;

    for(int i=0;i<a.length;i++){
        if(a[i]<max){
            if(a[i]>secondMax){
                secondMax=a[i];
            }
            continue;
        }

        if(a[i]>max){
            secondMax=max;
            max=a[i];
        }

    }
    return secondMax;
}
0
nikhil
int max,secondMax;
max=secondMax=array[0];
                                                for(int i=0;i<array.length;i++)
    {                                                   if(array[i]>max)                                                    {                                           max=array[i];                                                   }
                                                        if(array[i]>secondMax && array[i]<max)                                                  {
    secondMax=array[i];                                                 }
    }
0
Fakhar uz zaman

La limite supérieure doit être n + log2⁡n − 2, mais elle doit être supérieure à O(n) dans le cas d'un algorithme de sélection aléatoire, mais dans le pire des cas, elle est beaucoup plus petite. La solution pourrait être

  1. construire un arbre comme pour trouver l'élément MAX avec n - 1 comparaisons

    max (N)/\ max (N/2) max (N/2)

  2. enlever le MAX et retrouver le MAX log2n - 1 comparaison

PS Il utilise plus de mémoire, mais il est plus rapide que l'algorithme de sélection aléatoire dans le pire des cas.

0
vasste