Xinus
Xinus

Reputation: 30583

How can we find second maximum from array efficiently?

Is it possible to find the second maximum number from an array of integers by traversing the array only once?

As an example, I have a array of five integers from which I want to find second maximum number. Here is an attempt I gave in the 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;
}

The interviewer, however, came up with the test case int arr[6]={5,4,3,2,1,0};, which prevents it from going to the if condition the second time. I said to the interviewer that the only way would be to parse the array two times (two for loops). Does anybody have a better solution?

Upvotes: 19

Views: 42106

Answers (16)

Bunny
Bunny

Reputation: 1

#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;
}

Upvotes: 0

avakar
avakar

Reputation: 32685

The easiest solution would be to use std::nth_element.

Upvotes: 16

Fakhar uz zaman
Fakhar uz zaman

Reputation: 341

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

Upvotes: 0

SJHowe
SJHowe

Reputation: 776

How about the following below. make_heap is O(n) so this is efficient and this is 1-pass We find the second max by taking advantage that it must be one of the heap children of the parent, which had the 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;
}

Upvotes: 0

mitta
mitta

Reputation: 11

Check this 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];
}

Upvotes: 1

jhon
jhon

Reputation: 87

Can't we just sort this in decreasing order and take the 2nd element from the sorted array?

Upvotes: 0

vasste
vasste

Reputation: 56

The upper bound should have be n+log2⁡n−2, but it bigger than O(n) in case of random selection algorithm, but in worst case it much smaller. The solution might be

  1. build a tree like to find the MAX element with n - 1 comparisons

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

  2. remove the MAX and find the MAX again log2n - 1 comparison

PS. It uses additional memory, but it faster than random selection algorithm in worst case.

Upvotes: 0

nikhil
nikhil

Reputation: 9

Here is something which may work ,

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

Upvotes: 0

tianya
tianya

Reputation: 103

// Set the first two different numbers as the maximum and second maximum numbers

 int max = array[0];
 int i = 1;
//n is the amount of numbers

 while (array[i] == max && i < n) i++;
 int sec_max = array[i];
 if( max < sec_max ) {
    tmp = sec_max;
    sec_max = max;
    max = tmp;
 }

//find the second maximum number

 for( ; i < n; ++i ) {
   if( array[i] > max ) {
     sec_max = max;
     max = array[i];
   } else if( array[i] > sec_max && array[i] != max ) {
     sec_max = array[i];
   }
 }
 printf("The second maximum number is %d\n", sec_max);

Upvotes: -1

Boolean
Boolean

Reputation: 14660

Other way to solve this problem, is to use comparisons among the elements. Like for example,

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

Compare 1,2 and say max = 2 and second max = 1

Now compare 3 and 4 and compare the greatest of them with max.

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

The advantage with this is, you are eliminating two numbers in just two comparisons.

Let me know, if you have any problem understanding this.

Upvotes: 1

Rajendra Uppal
Rajendra Uppal

Reputation: 19964

Step 1. Decide on first two numbers.
Step 2. Loop through remaining numbers.
Step 3. Maintain latest maximum and second maximum.
Step 4. When updating second maximum, be aware that you are not making maximum and second maximum equal.

Tested for sorted input (ascending and descending), random input, input having duplicates, works fine.

#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;
}

Upvotes: 1

Martin
Martin

Reputation: 12403

Quickselect is the way to go with this one. Pseudo code is available at that link so I shall just explain the overall algorithm:

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

This is quite obviously based on the good old quicksort algorithm.

Following this algorithm through, always selecting element zero as the pivot every time:

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

This will leave your array in an undefined order afterwards, it's up to you if that's a problem.

Upvotes: 1

codaddict
codaddict

Reputation: 455460

Your initialization of max and second_max to -1 is flawed. What if the array has values like {-2,-3,-4}?

What you can do instead is to take the first 2 elements of the array (assuming the array has at least 2 elements), compare them, assign the smaller one to second_max and the larger one to max:

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

Then start comparing from the 3rd element and update max and/or second_max as needed:

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

Upvotes: 30

Johann Gerell
Johann Gerell

Reputation: 25601

Here you are:

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

Upvotes: 2

Hans Passant
Hans Passant

Reputation: 942508

Your original code is okay, you just have to initialize the max and second_max variables. Use the first two elements in the array.

Upvotes: 2

Anders Abel
Anders Abel

Reputation: 69300

You need a second 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];
   }
 }

Upvotes: 7

Related Questions