Find Min & Max in an Array Using Minimum Comparisons

Given an array of integers find the maximum and minimum elements by using minimum comparisons.

Naive Solution

We can simply iterate through the array and compare twice to each element to get min and max. This leads to 2n comparisons.

//sudo code
max = A[0], min = A[0]
for each i in A
    if A[i]>max then max = A[i]
    if A[i]<min then min = A[i]
public static void minmax0(int[] a) {
	if (a == null || a.length < 1)
		return;
 
	int min = a[0];
	int max = a[0];
 
	for (int i = 1; i <= a.length - 1; i++) {
		if (max < a[i]) {
			max = a[i];
		}
 
		if (min > a[i]) {
			min = a[i];
		}
	}
 
	System.out.println("min: " + min + "\nmax: " + max);
}

# of comparisons: 2(n-1).

Apparently, we should do better than this.

Better Solution 1

public static void minmax1(int[] a) {
 
	if (a == null || a.length < 1)
		return;
 
	int min, max;
 
	// if only one element
	if (a.length == 1) {
		max = a[0];
		min = a[0];
		System.out.println("min: " + min + "\nmax: " + max);
		return;
	}
 
	if (a[0] > a[1]) {
		max = a[0];
		min = a[1];
	} else {
		max = a[1];
		min = a[0];
	}
 
	for (int i = 2; i <= a.length - 1; i++) {
		if (max < a[i]) {
			max = a[i];
		} else if (min > a[i]) {
			min = a[i];
		}
	}
 
	System.out.println("min: " + min + "\nmax: " + max);
}

# of comparisons in worst case: 1 + 2(n-2) = 2n -1
# of comparisons in best case: 1 + (n–2) = n -1
# of comparisons on average: 1.5n -1

In the above implementation, worst case occurs when elements are sorted in descending order, because every time max is greater than a[i] and the second condition always gets executed. The best case occurs when elements are sorted in ascending order, because every time max is less than a[i] and the second condition never gets executed.

Better Solution 2

The number of comparisons can be reduced by comparing pairs first:

public static void minmax2(int[] a) {
	if (a == null || a.length < 1)
		return;
 
	int min, max;
 
	// if only one element
	if (a.length == 1) {
		max = a[0];
		min = a[0];
		System.out.println("min: " + min + "\nmax: " + max);
		return;
	}
 
	if (a[0] > a[1]) {
		max = a[0];
		min = a[1];
	} else {
		max = a[1];
		min = a[0];
	}
 
	for (int i = 2; i <= a.length - 2;) {
		if (a[i] > a[i + 1]) {
			min = Math.min(min, a[i + 1]);
			max = Math.max(max, a[i]);
		} else {
			min = Math.min(min, a[i]);
			max = Math.max(max, a[i + 1]);
		}
 
		i = i + 2;
	}
 
	if (a.length % 2 == 1) {
		min = Math.min(min, a[a.length - 1]);
		max = Math.max(max, a[a.length - 1]);
	}
 
	System.out.println("min: " + min + "\nmax: " + max);
}

# of comparisons when n is even: 1 + 3 * ((n-2)/2) = 1.5n-2.
# of comparisons when n is odd: 1 + 3 * ((n-3)/2) + 2 = 1.5n

Better Solution 3

class Pair {
	int min;
	int max;
}
 
public class Solution {
 
	public static Pair getMinMax(int arr[], int low, int high) {
		Pair result = new Pair();
		Pair left = new Pair();
		Pair right = new Pair();
 
		// if there is only one element
		if (low == high) {
			result.max = arr[low];
			result.min = arr[low];
			return result;
		}
 
		// if there are two elements
		if (high == low + 1) {
			if (arr[low] > arr[high]) {
				result.max = arr[low];
				result.min = arr[high];
			} else {
				result.max = arr[high];
				result.min = arr[low];
			}
			return result;
		}
 
		// if there are more than 2 elements
		int mid = (low + high) / 2;
		left = getMinMax(arr, low, mid);
		right = getMinMax(arr, mid + 1, high);
 
		if (left.min < right.min)
			result.min = left.min;
		else
			result.min = right.min;
 
		if (left.max > right.max)
			result.max = left.max;
		else
			result.max = right.max;
 
		return result;
	}
 
	public static void main(String[] args) {
		int a1[] = { 3, 4, 2, 6, 8, 1, 9, 12, 15, 11 };
		Pair result = getMinMax(a1, 0, a1.length - 1);
 
		System.out.println("Min: " + result.min);
		System.out.println("Max: " + result.max);
	}
}

# of Comparisons:

T(1) = 0
T(2) = 1
T(n) = T(floor(n/2)) + T(ceil(n/2)) + 2  ~ 2(T(n/2) + 2 =  1.5n -2 

Conclusion

By optimization, we can reduce # of comparison from naive approach's 2n to 1.5n.

Category >> Algorithms  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>

  1. Sergey Palyanov on 2014-2-9

    Math.min() and Math.max() internally also use comparisons. So, better solution is actually 3*n+1.

  2. SubOptimal on 2014-2-10

    For me the best solution (without using Arrays.sort(a1)) is your solution #1
    With an array size of 10_000_000 int:

    solution #1: do 9_999_999 comparision without creating addtional objects
    solution #3: do 33_222_780 comparision and create 34_834_173 Pair objects

    as a comparision were counted
    if (low == high) {
    if (high == low + 1) {
    if (left.min right.max)

  3. Mayaandi on 2014-4-9

    I was about to write the same response.. saw yours and just up voted.

  4. Neel Sheyal on 2014-6-6

    Iterate through the array from beginning to end and compare the pairs of numbers. Find the local minimum and local maximum which takes (n/2) comparisons.
    Find global minimum from (n/2) local minimums and global maximum from (n/2) local maximums which takes (n/2) comparisons each.

    For more detail and code http://www.algoqueue.com/algoqueue/default/view/3997696/find-highest-and-lowest-element-in-an-array-with-minimum-comparisons

  5. NewGuy on 2015-1-14

    I think he’s correct that its 1.5n, he’s already assuming that Math.min() and Math.max() use comparisons. For proof, look at Better Solution 2, in the “odd” case. we have +2 being added onto the end, and that would have come from one Math.min() and Math.max() in his example

Leave a comment

*