Second minimum element using minimum comparisons
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.
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
#include <bits/stdc++.h>
using namespace std;
struct Node
{
int idx;
Node *left, *right;
};
Node *createNode( int idx)
{
Node *t = new Node;
t->left = t->right = NULL;
t->idx = idx;
return t;
}
void traverseHeight(Node *root, int arr[], int &res)
{
if (root == NULL || (root->left == NULL &&
root->right == NULL))
return ;
if (res > arr[root->left->idx] &&
root->left->idx != root->idx)
{
res = arr[root->left->idx];
traverseHeight(root->right, arr, res);
}
else if (res > arr[root->right->idx] &&
root->right->idx != root->idx)
{
res = arr[root->right->idx];
traverseHeight(root->left, arr, res);
}
}
void findSecondMin( int arr[], int n)
{
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)
{
t2 = createNode(i + 1);
root = (arr[i] < arr[i + 1])? createNode(i) :
createNode(i + 1);
root->left = t1;
root->right = t2;
li.push_back(root);
}
else
li.push_back(t1);
}
int lsize = li.size();
while (lsize != 1)
{
int last = (lsize & 1)? (lsize - 2) : (lsize - 1);
for ( int i = 0; i < last; i += 2)
{
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);
root->left = f1;
root->right = f2;
li.push_back(root);
}
if (lsize & 1)
{
li.push_back(li.front());
li.pop_front();
}
lsize = li.size();
}
int res = INT_MAX;
traverseHeight(root, arr, res);
cout << "Minimum: " << arr[root->idx]
<< ", Second minimum: " << res << endl;
}
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;
class Node {
int idx;
Node left, right;
}
class GFG {
static Node createNode( int idx) {
Node t = new Node();
t.left = t.right = null ;
t.idx = idx;
return t;
}
static void traverseHeight(Node root, int [] arr, int [] res) {
if (root == null || (root.left == null && root.right == null ))
return ;
if (res[ 0 ] > arr[root.left.idx] && root.left.idx != root.idx) {
res[ 0 ] = arr[root.left.idx];
traverseHeight(root.right, arr, res);
}
else if (res[ 0 ] > arr[root.right.idx] && root.right.idx != root.idx) {
res[ 0 ] = arr[root.right.idx];
traverseHeight(root.left, arr, res);
}
}
static void findSecondMin( int [] arr, int n) {
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) {
t2 = createNode(i + 1 );
root = (arr[i] < arr[i + 1 ]) ? createNode(i) : createNode(i + 1 );
root.left = t1;
root.right = t2;
li.add(root);
} else
li.add(t1);
}
int lsize = li.size();
while (lsize != 1 ) {
int last = (lsize & 1 ) == 1 ? lsize - 2 : lsize - 1 ;
for ( int i = 0 ; i < last; i += 2 ) {
Node f1 = li.remove( 0 );
Node f2 = li.remove( 0 );
root = (arr[f1.idx] < arr[f2.idx]) ? createNode(f1.idx) : createNode(f2.idx);
root.left = f1;
root.right = f2;
li.add(root);
}
if ((lsize & 1 ) == 1 ) {
li.add(li.get( 0 ));
li.remove( 0 );
}
lsize = li.size();
}
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
class Node:
def __init__( self , idx):
self .idx = idx
self .left = None
self .right = None
def createNode(idx):
t = Node(idx)
t.left = None
t.right = None
return t
def traverseHeight(root, arr, res):
if root is None or (root.left is None and root.right is None ):
return res
if res > arr[root.left.idx] and root.left.idx ! = root.idx:
res = arr[root.left.idx]
if res > arr[root.right.idx] and root.right.idx ! = root.idx:
res = arr[root.right.idx]
res = traverseHeight(root.left, arr, res)
res = traverseHeight(root.right, arr, res)
return res
def findSecondMin(arr, n):
li = []
root = None
for i in range ( 0 , n, 2 ):
t1 = createNode(i)
t2 = None
if i + 1 < n:
t2 = createNode(i + 1 )
root = createNode(i) if arr[i] < arr[i + 1 ] else createNode(i + 1 )
root.left = t1
root.right = t2
li.append(root)
else :
li.append(t1)
lsize = len (li)
while lsize ! = 1 :
last = lsize - 2 if lsize % 2 = = 1 else lsize - 1
for i in range ( 0 , last, 2 ):
f1 = li.pop( 0 )
f2 = li.pop( 0 )
root = createNode(
f1.idx) if arr[f1.idx] < arr[f2.idx] else createNode(f2.idx)
root.left = f1
root.right = f2
li.append(root)
if lsize % 2 = = 1 :
li.append(li[ 0 ])
li.pop( 0 )
lsize = len (li)
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)
if __name__ = = '__main__' :
arr = [ 61 , 6 , 100 , 9 , 10 , 12 , 17 ]
n = len (arr)
findSecondMin(arr, n)
|
C#
using System;
using System.Collections.Generic;
class Node
{
public int idx;
public Node left, right;
}
class Program
{
static Node CreateNode( int idx)
{
Node t = new Node();
t.left = t.right = null ;
t.idx = idx;
return t;
}
static void TraverseHeight(Node root, int [] arr, ref int res)
{
if (root == null || (root.left == null && root.right == null ))
return ;
if (res > arr[root.left.idx] && root.left.idx != root.idx)
{
res = arr[root.left.idx];
TraverseHeight(root.right, arr, ref res);
}
else if (res > arr[root.right.idx] && root.right.idx != root.idx)
{
res = arr[root.right.idx];
TraverseHeight(root.left, arr, ref res);
}
}
static void FindSecondMin( int [] arr, int n)
{
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)
{
t2 = CreateNode(i + 1);
root = (arr[i] < arr[i + 1]) ? CreateNode(i) : CreateNode(i + 1);
root.left = t1;
root.right = t2;
li.Add(root);
}
else
li.Add(t1);
}
int lsize = li.Count;
while (lsize != 1)
{
int last = (lsize & 1) == 1 ? lsize - 2 : lsize - 1;
for ( int i = 0; i < last; i += 2)
{
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);
root.left = f1;
root.right = f2;
li.Add(root);
}
if ((lsize & 1) == 1)
{
li.Add(li[0]);
li.RemoveAt(0);
}
lsize = li.Count;
}
int res = int .MaxValue;
TraverseHeight(root, arr, ref res);
Console.WriteLine($ "Minimum: {arr[root.idx]}, Second minimum: {res}" );
}
static void Main()
{
int [] arr = { 61, 6, 100, 9, 10, 12, 17 };
int n = arr.Length;
FindSecondMin(arr, n);
}
}
|
Javascript
class Node {
constructor(idx) {
this .idx = idx;
this .left = null ;
this .right = null ;
}
}
function createNode(idx) {
return new Node(idx);
}
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);
}
}
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}`);
}
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.
Last Updated :
25 Nov, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...