Open In App

Second minimum element using minimum comparisons

Last Updated : 25 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array of integers, find the minimum (or maximum) element and the element just greater (or smaller) than that in less than 2n comparisons. The given array is not necessarily sorted. Extra space is allowed. 

Examples:

Input: {3, 6, 100, 9, 10, 12, 7, -1, 10}
Output: Minimum: -1, Second minimum: 3

We have already discussed an approach in below post. 

Find the smallest and second smallest element in an array 

Comparisons of array elements can be costly if array elements are of large size, for example large strings. We can minimize the number of comparisons used in above approach. The idea is based on tournament tree. Consider each element in the given array as a leaf node.

 tournamenttree 

First, we find the minimum element as explained by building a tournament tree. 

To build the tree, we compare all adjacent pairs of elements (leaf nodes) with each other. Now we have n/2 elements which are smaller than their counterparts (from each pair, the smaller element forms the level above that of the leaves). Again, find the smaller elements in each of the n/4 pairs. Continue this process until the root of the tree is created. The root is the minimum. 

Next, we traverse the tree and while doing so, we discard the sub trees whose root is greater than the smallest element. Before discarding, we update the second smallest element, which will hold our result. The point to understand here is that the tree is height balanced and we have to spend only logn time to traverse all the elements that were ever compared to the minimum in step 1. 

Thus, the overall time complexity is n + logn
Auxiliary space needed is O(2n), as the number of leaf nodes will be approximately equal to the number of internal nodes. 

CPP




// C++ program to find minimum and second minimum
// using minimum number of comparisons
#include <bits/stdc++.h>
using namespace std;
 
// Tournament Tree node
struct Node
{
    int idx;
    Node *left, *right;
};
 
// Utility function to create a tournament tree node
Node *createNode(int idx)
{
    Node *t = new Node;
    t->left = t->right = NULL;
    t->idx = idx;
    return t;
}
 
// This function traverses tree across height to
// find second smallest element in tournament tree.
// Note that root is smallest element of tournament
// tree.
void traverseHeight(Node *root, int arr[], int &res)
{
    // Base case
    if (root == NULL || (root->left == NULL &&
                        root->right == NULL))
        return;
 
    // If left child is smaller than current result,
    // update result and recur for left subarray.
    if (res > arr[root->left->idx] &&
    root->left->idx != root->idx)
    {
        res = arr[root->left->idx];
        traverseHeight(root->right, arr, res);
    }
 
    // If right child is smaller than current result,
    // update result and recur for left subarray.
    else if (res > arr[root->right->idx] &&
            root->right->idx != root->idx)
    {
        res = arr[root->right->idx];
        traverseHeight(root->left, arr, res);
    }
}
 
// Prints minimum and second minimum in arr[0..n-1]
void findSecondMin(int arr[], int n)
{
    // Create a list to store nodes of current
    // level
    list<Node *> li;
 
    Node *root = NULL;
    for (int i = 0; i < n; i += 2)
    {
        Node *t1 = createNode(i);
        Node *t2 = NULL;
        if (i + 1 < n)
        {
            // Make a node for next element
            t2 = createNode(i + 1);
 
            // Make smaller of two as root
            root = (arr[i] < arr[i + 1])? createNode(i) :
                                    createNode(i + 1);
 
            // Make two nodes as children of smaller
            root->left = t1;
            root->right = t2;
 
            // Add root
            li.push_back(root);
        }
        else
            li.push_back(t1);
    }
 
    int lsize = li.size();
 
    // Construct the complete tournament tree from above
    // prepared list of winners in first round.
    while (lsize != 1)
    {
        // Find index of last pair
        int last = (lsize & 1)? (lsize - 2) : (lsize - 1);
 
        // Process current list items in pair
        for (int i = 0; i < last; i += 2)
        {
            // Extract two nodes from list, make a new
            // node for winner of two
            Node *f1 = li.front();
            li.pop_front();
 
            Node *f2 = li.front();
            li.pop_front();
            root = (arr[f1->idx] < arr[f2->idx])?
                createNode(f1->idx) : createNode(f2->idx);
 
            // Make winner as parent of two
            root->left = f1;
            root->right = f2;
 
            // Add winner to list of next level
            li.push_back(root);
        }
        if (lsize & 1)
        {
            li.push_back(li.front());
            li.pop_front();
        }
        lsize = li.size();
    }
 
    // Traverse tree from root to find second minimum
    // Note that minimum is already known and root of
    // tournament tree.
    int res = INT_MAX;
    traverseHeight(root, arr, res);
    cout << "Minimum: " << arr[root->idx]
        << ", Second minimum: " << res << endl;
}
 
// Driver code
int main()
{
    int arr[] = {61, 6, 100, 9, 10, 12, 17};
    int n = sizeof(arr)/sizeof(arr[0]);
    findSecondMin(arr, n);
    return 0;
}


Java




import java.util.LinkedList;
import java.util.List;
 
// Tournament Tree node
class Node {
    int idx;
    Node left, right;
}
 
class GFG {
    // Utility function to create a tournament tree node
    static Node createNode(int idx) {
        Node t = new Node();
        t.left = t.right = null;
        t.idx = idx;
        return t;
    }
 
    // This function traverses the tree across height to
    // find the second smallest element in the tournament tree.
    // Note that the root is the smallest element of the tournament tree.
    static void traverseHeight(Node root, int[] arr, int[] res) {
        // Base case
        if (root == null || (root.left == null && root.right == null))
            return;
 
        // If the left child is smaller than the current result,
        // update the result and recur for the left subarray.
        if (res[0] > arr[root.left.idx] && root.left.idx != root.idx) {
            res[0] = arr[root.left.idx];
            traverseHeight(root.right, arr, res);
        }
 
        // If the right child is smaller than the current result,
        // update the result and recur for the left subarray.
        else if (res[0] > arr[root.right.idx] && root.right.idx != root.idx) {
            res[0] = arr[root.right.idx];
            traverseHeight(root.left, arr, res);
        }
    }
 
    // Prints minimum and second minimum in arr[0..n-1]
    static void findSecondMin(int[] arr, int n) {
        // Create a list to store nodes of the current level
        List<Node> li = new LinkedList<>();
 
        Node root = null;
        for (int i = 0; i < n; i += 2) {
            Node t1 = createNode(i);
            Node t2 = null;
            if (i + 1 < n) {
                // Make a node for the next element
                t2 = createNode(i + 1);
 
                // Make the smaller of the two as the root
                root = (arr[i] < arr[i + 1]) ? createNode(i) : createNode(i + 1);
 
                // Make two nodes as children of the smaller
                root.left = t1;
                root.right = t2;
 
                // Add root
                li.add(root);
            } else
                li.add(t1);
        }
 
        int lsize = li.size();
 
        // Construct the complete tournament tree from the above
        // prepared list of winners in the first round.
        while (lsize != 1) {
            // Find the index of the last pair
            int last = (lsize & 1) == 1 ? lsize - 2 : lsize - 1;
 
            // Process current list items in pairs
            for (int i = 0; i < last; i += 2) {
                // Extract two nodes from the list, make a new
                // node for the winner of the two
                Node f1 = li.remove(0);
                Node f2 = li.remove(0);
                root = (arr[f1.idx] < arr[f2.idx]) ? createNode(f1.idx) : createNode(f2.idx);
 
                // Make the winner the parent of the two
                root.left = f1;
                root.right = f2;
 
                // Add the winner to the list of the next level
                li.add(root);
            }
            if ((lsize & 1) == 1) {
                li.add(li.get(0));
                li.remove(0);
            }
            lsize = li.size();
        }
 
        // Traverse the tree from the root to find the second minimum
        // Note that the minimum is already known and is the root of
        // the tournament tree.
        int[] res = {Integer.MAX_VALUE};
        traverseHeight(root, arr, res);
        System.out.println("Minimum: " + arr[root.idx] + ", Second minimum: " + res[0]);
    }
 
    public static void main(String[] args) {
        int arr[] = {61, 6, 100, 9, 10, 12, 17};
        int n = arr.length;
        findSecondMin(arr, n);
    }
}


Python3




# Python program to find minimum and second minimum
# using minimum number of comparisons
 
# Tournament Tree node
class Node:
    def __init__(self, idx):
        self.idx = idx
        self.left = None
        self.right = None
 
# Utility function to create a tournament tree node
def createNode(idx):
    t = Node(idx)
    t.left = None
    t.right = None
    return t
 
# This function traverses tree across height to
# find second smallest element in tournament tree.
# Note that root is smallest element of tournament
# tree.
def traverseHeight(root, arr, res):
    # Base case
    if root is None or (root.left is None and root.right is None):
        return res
 
    # If left child is smaller than current result,
    # update result and recur for left subarray.
    if res > arr[root.left.idx] and root.left.idx != root.idx:
        res = arr[root.left.idx]
 
    # If right child is smaller than current result,
    # update result and recur for left subarray.
    if res > arr[root.right.idx] and root.right.idx != root.idx:
        res = arr[root.right.idx]
 
    # Recur for the child nodes
    res = traverseHeight(root.left, arr, res)
    res = traverseHeight(root.right, arr, res)
 
    return res
 
 
# Prints minimum and second minimum in arr[0..n-1]
def findSecondMin(arr, n):
    # Create a list to store nodes of current
    # level
    li = []
 
    root = None
    for i in range(0, n, 2):
        t1 = createNode(i)
        t2 = None
        if i + 1 < n:
            # Make a node for next element
            t2 = createNode(i + 1)
 
            # Make smaller of two as root
            root = createNode(i) if arr[i] < arr[i + 1] else createNode(i + 1)
 
            # Make two nodes as children of smaller
            root.left = t1
            root.right = t2
 
            # Add root
            li.append(root)
        else:
            li.append(t1)
 
    lsize = len(li)
 
    # Construct the complete tournament tree from above
    # prepared list of winners in first round.
    while lsize != 1:
        # Find index of last pair
        last = lsize - 2 if lsize % 2 == 1 else lsize - 1
 
        # Process current list items in pair
        for i in range(0, last, 2):
            # Extract two nodes from list, make a new
            # node for winner of two
            f1 = li.pop(0)
            f2 = li.pop(0)
            root = createNode(
                f1.idx) if arr[f1.idx] < arr[f2.idx] else createNode(f2.idx)
 
            # Make winner as parent of two
            root.left = f1
            root.right = f2
 
            # Add winner to list of next level
            li.append(root)
        if lsize % 2 == 1:
            li.append(li[0])
            li.pop(0)
        lsize = len(li)
 
    # Traverse tree from root to find second minimum
    # Note that minimum is already known and root of
    # tournament tree.
    res = float('inf')
    for i in range(len(li)):
        if li[i].idx == root.idx:
            root = li[i]
            break
    res = traverseHeight(root, arr, res)
    print("Minimum:", arr[root.idx], ", Second minimum:", res)
 
# Driver code
if __name__ == '__main__':
    arr = [61, 6, 100, 9, 10, 12, 17]
    n = len(arr)
    findSecondMin(arr, n)


C#




using System;
using System.Collections.Generic;
 
// Tournament Tree node
class Node
{
    public int idx;
    public Node left, right;
}
 
class Program
{
    // Utility function to create a tournament tree node
    static Node CreateNode(int idx)
    {
        Node t = new Node();
        t.left = t.right = null;
        t.idx = idx;
        return t;
    }
 
    // This function traverses the tree across height to
    // find the second smallest element in the tournament tree.
    // Note that the root is the smallest element of the tournament tree.
    static void TraverseHeight(Node root, int[] arr, ref int res)
    {
        // Base case
        if (root == null || (root.left == null && root.right == null))
            return;
 
        // If the left child is smaller than the current result,
        // update the result and recur for the left subarray.
        if (res > arr[root.left.idx] && root.left.idx != root.idx)
        {
            res = arr[root.left.idx];
            TraverseHeight(root.right, arr, ref res);
        }
 
        // If the right child is smaller than the current result,
        // update the result and recur for the left subarray.
        else if (res > arr[root.right.idx] && root.right.idx != root.idx)
        {
            res = arr[root.right.idx];
            TraverseHeight(root.left, arr, ref res);
        }
    }
 
    // Prints minimum and second minimum in arr[0..n-1]
    static void FindSecondMin(int[] arr, int n)
    {
        // Create a list to store nodes of the current level
        List<Node> li = new List<Node>();
 
        Node root = null;
        for (int i = 0; i < n; i += 2)
        {
            Node t1 = CreateNode(i);
            Node t2 = null;
            if (i + 1 < n)
            {
                // Make a node for the next element
                t2 = CreateNode(i + 1);
 
                // Make the smaller of the two as the root
                root = (arr[i] < arr[i + 1]) ? CreateNode(i) : CreateNode(i + 1);
 
                // Make two nodes as children of the smaller root
                root.left = t1;
                root.right = t2;
 
                // Add root
                li.Add(root);
            }
            else
                li.Add(t1);
        }
 
        int lsize = li.Count;
 
        // Construct the complete tournament tree from the above
        // prepared list of winners in the first round.
        while (lsize != 1)
        {
            // Find the index of the last pair
            int last = (lsize & 1) == 1 ? lsize - 2 : lsize - 1;
 
            // Process current list items in pairs
            for (int i = 0; i < last; i += 2)
            {
                // Extract two nodes from the list, make a new
                // node for the winner of the two
                Node f1 = li[0];
                li.RemoveAt(0);
 
                Node f2 = li[0];
                li.RemoveAt(0);
                root = (arr[f1.idx] < arr[f2.idx]) ?
                    CreateNode(f1.idx) : CreateNode(f2.idx);
 
                // Make the winner the parent of the two
                root.left = f1;
                root.right = f2;
 
                // Add the winner to the list of the next level
                li.Add(root);
            }
            if ((lsize & 1) == 1)
            {
                li.Add(li[0]);
                li.RemoveAt(0);
            }
            lsize = li.Count;
        }
 
        // Traverse the tree from root to find the second minimum
        // Note that the minimum is already known as the root of the tournament tree.
        int res = int.MaxValue;
        TraverseHeight(root, arr, ref res);
        Console.WriteLine($"Minimum: {arr[root.idx]}, Second minimum: {res}");
    }
 
    // Driver code
    static void Main()
    {
        int[] arr = { 61, 6, 100, 9, 10, 12, 17 };
        int n = arr.Length;
        FindSecondMin(arr, n);
    }
}


Javascript




// Tournament Tree Node
class Node {
    constructor(idx) {
        this.idx = idx;
        this.left = null;
        this.right = null;
    }
}
 
// Create a node
function createNode(idx) {
    return new Node(idx);
}
 
// Traverse the tree across height to find the second smallest element
function traverseHeight(root, arr, result) {
    if (root === null || (!root.left && !root.right)) {
        return;
    }
 
    if (result > arr[root.left.idx] && root.left.idx !== root.idx) {
        result = arr[root.left.idx];
        traverseHeight(root.right, arr, result);
    } else if (result > arr[root.right.idx] && root.right.idx !== root.idx) {
        result = arr[root.right.idx];
        traverseHeight(root.left, arr, result);
    }
}
 
// Find minimum and second minimum in arr[0..n-1]
function findSecondMin(arr) {
    let n = arr.length;
    let li = [];
 
    let root = null;
    for (let i = 0; i < n; i += 2) {
        let t1 = createNode(i);
        let t2 = null;
 
        if (i + 1 < n) {
            t2 = createNode(i + 1);
            root = arr[i] < arr[i + 1] ? createNode(i) : createNode(i + 1);
            root.left = t1;
            root.right = t2;
            li.push(root);
        } else {
            li.push(t1);
        }
    }
 
    let lsize = li.length;
 
    while (lsize !== 1) {
        let last = (lsize & 1) ? lsize - 2 : lsize - 1;
        for (let i = 0; i < last; i += 2) {
            let f1 = li.shift();
            let f2 = li.shift();
            root = arr[f1.idx] < arr[f2.idx] ? createNode(f1.idx) : createNode(f2.idx);
            root.left = f1;
            root.right = f2;
            li.push(root);
        }
        if (lsize & 1) {
            li.push(li[0]);
            li.shift();
        }
        lsize = li.length;
    }
 
    let res = Number.MAX_SAFE_INTEGER;
    traverseHeight(li[0], arr, res);
    console.log(`Minimum: ${arr[li[0].idx]}, Second minimum: ${res}`);
}
 
// Driver code
const arr = [61, 6, 100, 9, 10, 12, 17];
findSecondMin(arr);


Output:

Minimum: 6, Second minimum: 9

We can optimize above code by avoid creation of leaf nodes, as that information is stored in the array itself (and we know that the elements were compared in pairs). 

This article is contributed by Dhruv.



Similar Reads

Search an element in an unsorted array using minimum number of comparisons
Given an array of n distinct integers and an element x. Search the element x in the array using minimum number of comparisons. Any sort of comparison will contribute 1 to the count of comparisons. For example, the condition used to terminate a loop, will also contribute 1 to the count of comparisons each time it gets executed. Expressions like whil
7 min read
Maximum and minimum of an array using minimum number of comparisons
Given an array of size N. The task is to find the maximum and the minimum element of the array using the minimum number of comparisons. Examples: Input: arr[] = {3, 5, 4, 1, 9}Output: Minimum element is: 1 Maximum element is: 9 Input: arr[] = {22, 14, 8, 17, 35, 3}Output: Minimum element is: 3 Maximum element is: 35 Recommended PracticeMax MinTry I
30 min read
Check if an element is present in an array using at most floor(N / 2) + 2 comparisons
Given an array A[] of size N and an integer X, the task is to check if X exists in A[] with no more than floor(N/2) + 2 comparisons. Note: For any index i, (i &lt; N) or (A[i] == X) are considered as separate comparisons. Examples: Input: A[] = {-3, 5, 11, 3, 100, 2, 88, 22, 7, 900, 23, 4, 1}, X = 88Output: Yes 8Explanation: X = 88 exists in the gi
7 min read
Middle of three using minimum comparisons
Given three distinct numbers a, b and c find the number with a value in middle. Examples: Input : a = 20, b = 30, c = 40 Output : 30 Input : a = 12, n = 32, c = 11 Output : 12 Simple Approach: C/C++ Code // CPP program to find middle of three distinct // numbers #include &lt;bits/stdc++.h&gt; using namespace std; int middleOfThree(int a, int b, int
13 min read
Minimum comparisons required to find the only heavier ball from N balls
Given N (N &gt; 1) number of balls and a weight balancing machine. There are N-1 balls of the same weight and one ball heavier than the others. The task is to find out the minimum number of times weighing is required to find the heavier ball where any number of balls can be weighted each time. Note: The weight balancing machine can tell relative we
5 min read
Comparisons involved in Modified Quicksort Using Merge Sort Tree
In QuickSort, ideal situation is when median is always chosen as pivot as this results in minimum time. In this article, Merge Sort Tree is used to find median for different ranges in QuickSort and number of comparisons are analyzed.Examples: Input : arr = {4, 3, 5, 1, 2} Output : 11 Explanation We have to make 11 comparisons when we apply quick so
19 min read
Number of comparisons in each direction for m queries in linear search
Given an array containing N distinct elements. There are M queries, each containing an integer X and asking for the index of X in the array. For each query, the task is to perform linear search X from left to right and count the number of comparisons it took to find X and do the same thing right to left. In the end, print the total number of compar
7 min read
How to make Mergesort to perform O(n) comparisons in best case?
As we know, Mergesort is a divide and conquer algorithm that splits the array to halves recursively until it reaches an array of the size of 1, and after that it merges sorted subarrays until the original array is fully sorted. Typical implementation of merge sort works in O(n Log n) time in all three cases (best, average and worst). We need to red
3 min read
Multiple comparisons in a C++ priority queue?
What is a Priority Queue? A Priority Queue is an abstract data type that is similar to a queue, and every element has some priority value associated with it. The priority of the elements in a priority queue determines the order in which elements are served (i.e., the order in which they are removed). If in any case, the elements have the same prior
5 min read
Find last element after deleting every second element in array of n integers
Given a circular array of size n containing integers from 1 to n. Find the last element that would remain in the list after erasing every second element starting from the first element. Example: Input: 5 Output: 3 Explanation Element in circular array are: 1 2 3 4 5 Starting from first element i.e, '1' delete every second element like this, 1 0 3 4
7 min read