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?
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];
}
}
La solution la plus simple serait d’utiliser std::nth_element
.
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];
}
}
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;
}
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.
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.
É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;
}
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.
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];
}
Ne pouvons-nous pas simplement trier cela par ordre décroissant et prendre le deuxième élément du tableau trié?
#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;
}
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;
}
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;
}
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]; }
}
La limite supérieure doit être n + log2n − 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
construire un arbre comme pour trouver l'élément MAX avec n - 1 comparaisons
max (N)/\ max (N/2) max (N/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.