7

Is it possible to find the 2 largest numbers in an array, and only loop through the collection once?

I had this as an interview question and didn't really get it in time.

Dan J
  • 16,319
  • 7
  • 50
  • 82
codecompleting
  • 9,251
  • 13
  • 61
  • 102
  • 15
    Yes, it is possible. Care to take a crack at a solution? – Eric Lippert Oct 18 '11 at 14:36
  • possible duplicate of [Algorithm to find k smallest numbers in array of n items](http://stackoverflow.com/questions/5380568/algorithm-to-find-k-smallest-numbers-in-array-of-n-items) – Nemo Oct 18 '11 at 15:05

3 Answers3

29

It seems pretty straightforward..

int[] nums = { 3, 1, 4, 1, 5, 9, 2, 6 };

int max1 = -1;
int max2 = -1;
foreach (int num in nums)
{
  if (num > max1) { max2 = max1; max1 = num; }
  else if (num > max2) { max2 = num; }
}    

For example:

// 3: max2 = -1; max1 = 3;
// 1: max2 = 1;
// 4: max2 = 3; max1 = 4;

Quick explanation:

  • Define -1 as a placeholder, could use int.MinValue, or better yet a separate bool to indicate no-match
  • If the value tested is bigger than the current maximum (max1), assign current maximum to max2, new value to max1
  • Else if must be smaller, but if it's bigger than second-maximum, assign new value to max2
Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
1

In general, you can find the K largest (or smallest) numbers in an array using a single pass for any K. The total time complexity will be O(NK), where N is the size of the array:

Keep a sorted list of numbers that has at most K elements. Walk though the array and for each item:

  1. if there list is not yet full, insert the item
  2. otherwise, if the item is bigger than the smallest item in the list, insert this item and remove the smallest one.

In the end, the list will contain K largest items, which is what we wanted.

This solution is quite slow, though. Using a self-balancing binary search tree or a skip list, you could get to O(N log K). (Since it's impossible to sort faster than O(N log N) in general case, and this method can be used for sorting the whole array if we set K = N, this looks like the best we can get.)

In the case of K = 2, you don't need all this heavy machinery. Just two variables representing the two positions in the list are enough.

svick
  • 236,525
  • 50
  • 385
  • 514
0

Yes, it is. As you traverse the list, keep a record of the largest number found and whenever you find a bigger number, save the largest found into a second largest found before updating the largest found. If the value is bigger than the second largest, then update the second largest value.

Skizz
  • 69,698
  • 10
  • 71
  • 108
  • 4
    You're missing a key step, see my answer: what happens when you get a value not bigger than the maximum, but bigger than the second-biggest? You need to store that as the new biggest – Kieren Johnstone Oct 18 '11 at 14:43
  • 1
    Have to agree with Kieron; say you have 9 and 7 saved as the two largest numbers, if the next number selected is 8 by your logic it will be discarded as it is less than 9 even though it is bigger than 7. Hope that makes sense. – Andy Rose Oct 18 '11 at 14:52
  • Oops. Fixed it. There is an edit button that anyone can use to fix things - why do people put the effort into putting a comment about the missing step rather than editing the post to add the extra step. I can't imagine it's that much harder to make the answer better rather than criticising it. Hmmm. Maybe people just like to complain ;-) – Skizz Oct 18 '11 at 21:26
  • 4
    @Skizz, well, there already was a correct answer. And many people tend not to make edits that completely change what an answer says. – svick Oct 18 '11 at 21:59
  • 2
    Editing is for helping clean up formatting, grammar, typos, commenting on dead links. Not editing all answers to be correct and equal to the already-posted correct answer :) – Kieren Johnstone Oct 19 '11 at 07:45