Second minimum element using minimum comparisons

Last Updated : 25 Nov, 2023

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.

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.

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 ` `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 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 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 li = ``new` `List();`   `        ``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).