0

I have been given an array of elements and an inbuilt function which can sort 5 elements at a time. How do I use only this function to obtain the largest 3 elements of the array with the least number of calls to this function?

The approach I have tried is dividing the array in groups of 5 each, applying the function on each group, and applying the function on the maximums obtained from each group.

This approach fails when the highest and second highest happen to be present in the same group. Is there a better approach to do this?

sharang gupta
  • 103
  • 4
  • 12
  • 5
    [Find the largest three elements in an array](https://www.geeksforgeeks.org/find-the-largest-three-elements-in-an-array/) – Ole V.V. Oct 09 '18 at 04:14
  • https://www.geeksforgeeks.org/find-the-largest-three-elements-in-an-array/ – kvk30 Oct 09 '18 at 04:15
  • 8
    Although this is an interesting question, Stackoverflow is not here to solve it for you. You need to show what you have already tried and where exactly you need help. – Ridcully Oct 09 '18 at 04:15
  • [Find top N elements in an Array](https://stackoverflow.com/questions/4084495/find-top-n-elements-in-an-array) – Ole V.V. Oct 09 '18 at 04:16
  • 1
    save any 3 elemnts element of your array into a 3-elemnts array so that your 3 elements are kept sorted and scan your original array and compare every element to the smallest of the 3 elemnts, if your current element is larger than it replace the smallest with it and re-sort the 3 elemnts –  Oct 09 '18 at 04:35
  • Thank you @blade, I think this is the approach. If you write an answer I'll upvote that. – sharang gupta Oct 09 '18 at 04:43
  • 1
    This reminds me of the 3 fastest horses problem. This can help to understand and solve the problem: http://puzzles.nigelcoldwell.co.uk/fiftynine.htm – findusl Oct 09 '18 at 08:47

4 Answers4

4

Since you have the built-in method to sort five elements I suggest: Sort the first five elements from the array. Repeatedly discard the two smallest of the five and replace with two more elements from the array (two elements that have not yet been considered), then sort the five again. In the end take the largest three of the five.

It will be possible to do a bit better than what I have sketched. Say you have 25 elements. For each group of 5 find the three largest. Then among the nos. 1 from each group find the three largest. The same for the nos. 2 from each group and the nos. 3. Now we can deduce that the three largest overall will be among the three largest nos. 1, the two largest nos. 2 and the single largest no. 3, that is six elements instead of 9. So we can find the three largest in just two more calls to your built-in method instead of three more calls. Generalizing the idea to any size of the original array will be complicated, though.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • That is the answer I am leaning towards as well... but is it the most efficient? – Charles Oct 09 '18 at 04:50
  • 1
    No, it isn’t really the most efficient (I assume you are talking about run time). For the most efficient use the links I posted in comments, they will perform slightly better. But they don’t use your built-in method. This is O(n), however, which is the best big-O complexity you can hope for. – Ole V.V. Oct 09 '18 at 04:52
1

How about this method.

  1. Divide the array into groups of 5
  2. Apply the provided sort method for each group of 5 elements
  3. Get the first 3 elements from each array
  4. Then merge the identified 3 elements in each group to one single array
  5. Now repeat from step 1 to 4, until the final array size is less than or equal to 5
  6. Get the first 3 elements from the final array
Rans
  • 422
  • 2
  • 8
  • As far as I can tell it will be as efficient as my suggestion, no more, no less. I would consider it more complicated. – Ole V.V. Oct 09 '18 at 04:59
  • That I agree too. Noticed your comment later. – Rans Oct 09 '18 at 05:08
  • @OleV.V. I disagree with you. your alg would require n/2 calls to complete. This one should be in some form of log(n). nice. – Charles Oct 09 '18 at 06:14
  • @Charles You will have to inspect all `n` elements in order to determine the three largest. This solution makes `n / 5` groups of 5, that alone takes O(n). More precisely both this suggestion and mine make `(n - 3) / 2` calls to the built-in method. – Ole V.V. Oct 09 '18 at 06:16
  • The n here isn't exactly the number of elements. try it with an example with 10 elements. his alg can do it with 4 compares for the worst case. you would need 8 compares no matter what. This difference grows with larger sets. Another way to thin about it is instead of 5 elements you can sort 6 at a time. Then it starts to look like a binary tree traversal.3 lower numbers become your left node and 3 larger becomes the right. – Charles Oct 09 '18 at 12:38
1
#include <iostream>


void sortThree(int res[3]) {
   for(int j = 0; j < 2; j++) {
      if(res[j] > res[j+1])
         std::swap(res[j], res[j+1]);
}
   if(res[0] > res[1]) std::swap(res[0], res[1]); // second pass
}

bool lsearch(int src[], int n, int k) {
  for(int i = 0; i < n; i++) {
    if(src[i] == k) return true;
  }
  return false;
}

void getThreeLargest(int arr[], int n, int res[3]) {
  res[0] = arr[0];
  res[1] = arr[1];
  res[2] = arr[2];
  sortThree(res);
  for(int i = 3; i < n; i++) {
    // if no repetition wanted
    // if(arr[i] > res[0] && !lsearch(res, 3, arr[i])) {
    if(arr[i] > res[0]) {
      res[0] = arr[i];
      sortThree(res);
    }
  }
}

int main(int argc, char *argv[])
{
  int arr[] = {91,21,3,-4,5,2,1,90,9,11};
  int res[3];
  getThreeLargest(arr, 10, res);
  for(int i = 0; i < 3; i++)
    std::cout << res[i] << '\n';
  return 0;
}

Very simple solution here in a c-way to do it. You can easily convert it to java. Scanning the array is O(n). Since the little array to be sorted and searched has only 3 elements we can easily use linear search to avoid repetition and sorting takes only 2 comparisons. It's still O(n).

  • 1
    There seems to be a slight bug in your code. When I use `int arr[] = { 2, 5, 5, 5 };`, I would expect 5, 5, 5, but I get 2, 5, 5. Your basic idea is valid. – Ole V.V. Oct 09 '18 at 06:22
  • 1
    let the asker fix it :P –  Oct 09 '18 at 06:34
  • 1
    The question is tagged with `java` - your code seems to be `C` – slartidan Oct 09 '18 at 07:06
  • it is an easy conversion. I stated that in the answer. Just use the console print function of java, put in a class, change the way of declaring the array and you're done. –  Oct 09 '18 at 07:08
  • fixed it, i had to eliminate the lsearch since i stated it was assuming no repetition –  Oct 09 '18 at 07:10
  • 1
    This doesn't fulfill the question's criterion "I have been given an array of elements and an inbuilt function which can sort 5 elements at a time. How do I use **only this function**…". – Chai T. Rex Oct 09 '18 at 07:31
-1
#include<stdio.h>
#include<limits.h>

int retmax(int *a,int n,int exc){

    int max = INT_MIN;
    for(int i=0;i<n;i++){
        if(a[i] > max && a[i] < exc)
           max = a[i];
    }

    return max;
}

int main(){

    int a[]={32,54,12,43,98,45,87};
    int size = sizeof(a)/sizeof(a[0]);

    int x = retmax(a,size,INT_MAX);
    int y = retmax(a,size,x);
    int z = retmax(a,size,y);

    printf("%d %d %d",x,y,z);
}

A simple O(n) solution.

  • You have *not* been given an array of integers. You don't know how to compare elements. You only know how to sort five elements at a time. – greybeard Jun 30 '19 at 06:17