Find smallest range containing elements from k lists

Given k sorted lists of integers of size n each, find the smallest range that includes at least element from each of the k lists. If more than one smallest ranges are found, print any one of them.

Example :

Input:
K = 3
arr1[] : [4, 7, 9, 12, 15]
arr2[] : [0, 8, 10, 14, 20]
arr3[] : [6, 12, 16, 30, 50]
Output:
The smallest range is [6 8] 
Explanation: Smallest range is formed by 
number 7 from first list, 8 from second
list and 6 from third list.


Input: 
k = 3
arr1[] : [4, 7]
arr2[] : [1, 2]
arr3[] : [20, 40]
The smallest range is [2 20]  

Naive approach : The idea is to maintain pointers to every list using array ptr[k].Below are the steps :

  1. Initially the index of every list is 0,therefore initialize every element of ptr[0..k] to 0;
  2. Repeat the following steps until atleast one list exhausts :
    • Now find the minimum and maximum value among the current elements of all the list pointed by the ptr[0…k] array.
    • Now update the minrange if current (max-min) is less than minrange.
    • increment the pointer pointing to current minimum element.

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to finds out smallest range that includes
// elements from each of the given sorted lists.
#include <bits/stdc++.h>
  
using namespace std;
  
#define N 5
  
// array for storing the current index of list i
int ptr[501];
  
// This function takes an k sorted lists in the form of
// 2D array as an argument. It finds out smallest range
// that includes elements from each of the k lists.
void findSmallestRange(int arr[][N], int n, int k)
{
      int i,minval,maxval,minrange,minel,maxel,flag,minind;
        
      //initializing to 0 index;
      for(i = 0;i <= k;i++) 
        ptr[i] = 0;
  
      minrange = INT_MAX;
        
      while(1)       
      {
            // for mainting the index of list containing the minimum element
          minind = -1; 
          minval = INT_MAX;
          maxval = INT_MIN;
          flag = 0;
  
          //iterating over all the list
          for(i = 0;i < k;i++)   
          {    
                // if every element of list[i] is traversed then break the loop
              if(ptr[i] == n)   
              {
                flag = 1;
                break;
              }
              // find minimum value among all the list elements pointing by the ptr[] array 
              if(ptr[i] < n && arr[i][ptr[i]] < minval)  
              {
                  minind=i;  // update the index of the list
                  minval=arr[i][ptr[i]];
              }
              // find maximum value among all the list elements pointing by the ptr[] array
              if(ptr[i] < n && arr[i][ptr[i]] > maxval)    
              {
                  maxval = arr[i][ptr[i]];
              }
          }
  
          //if any list exhaust we will not get any better answer ,so break the while loop
          if(flag) 
            break;
  
          ptr[minind]++;
  
          //updating the minrange
          if((maxval-minval) < minrange)  
          {
              minel = minval;
              maxel = maxval;
              minrange = maxel - minel;
          }
      }
        
      printf("The smallest range is [%d , %d]\n",minel,maxel);
}    
  
// Driver program to test above function
int main()
{
    int arr[][N] = {
                    {4, 7, 9, 12, 15},
                    {0, 8, 10, 14, 20},
                    {6, 12, 16, 30, 50}
                    };
  
    int k = sizeof(arr)/sizeof(arr[0]);
   
    findSmallestRange(arr,N,k);
   
    return 0;
}
// This code is contributed by Aditya Krishna Namdeo

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program to finds out smallest range that includes
// elements from each of the given sorted lists.
class GFG {
  
    static final int N = 5;
  
// array for storing the current index of list i
    static int ptr[] = new int[501];
  
// This function takes an k sorted lists in the form of
// 2D array as an argument. It finds out smallest range
// that includes elements from each of the k lists.
    static void findSmallestRange(int arr[][], int n, int k) {
        int i, minval, maxval, minrange, minel = 0, maxel = 0, flag, minind;
  
        //initializing to 0 index;
        for (i = 0; i <= k; i++) {
            ptr[i] = 0;
        }
  
        minrange = Integer.MAX_VALUE;
  
        while (true) {
            // for mainting the index of list containing the minimum element
            minind = -1;
            minval = Integer.MAX_VALUE;
            maxval = Integer.MIN_VALUE;
            flag = 0;
  
            //iterating over all the list
            for (i = 0; i < k; i++) {
                // if every element of list[i] is traversed then break the loop
                if (ptr[i] == n) {
                    flag = 1;
                    break;
                }
                // find minimum value among all the list elements pointing by the ptr[] array 
                if (ptr[i] < n && arr[i][ptr[i]] < minval) {
                    minind = i;  // update the index of the list
                    minval = arr[i][ptr[i]];
                }
                // find maximum value among all the list elements pointing by the ptr[] array
                if (ptr[i] < n && arr[i][ptr[i]] > maxval) {
                    maxval = arr[i][ptr[i]];
                }
            }
  
            //if any list exhaust we will not get any better answer ,so break the while loop
            if (flag == 1) {
                break;
            }
  
            ptr[minind]++;
  
            //updating the minrange
            if ((maxval - minval) < minrange) {
                minel = minval;
                maxel = maxval;
                minrange = maxel - minel;
            }
        }
        System.out.printf("The smallest range is [%d , %d]\n", minel, maxel);
    }
  
// Driver program to test above function
    public static void main(String[] args) {
  
        int arr[][] = {
            {4, 7, 9, 12, 15},
            {0, 8, 10, 14, 20},
            {6, 12, 16, 30, 50}
        };
  
        int k = arr.length;
  
        findSmallestRange(arr, N, k);
  
    }
}
//this code contributed by Rajput-Ji

chevron_right


Python

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 program to finds out 
# smallest range that includes
# elements from each of the 
# given sorted lists.
  
N = 5
  
# array for storing the 
# current index of list i
ptr = [0 for i in range(501)]
  
# This function takes an k sorted 
# lists in the form of 2D array as 
# an argument. It finds out smallest
# range that includes elements from 
# each of the k lists.
def findSmallestRange(arr, n, k):
  
    i, minval, maxval, minrange, minel, maxel, flag, minind = 0, 0, 0, 0, 0, 0, 0, 0
          
    # initializing to 0 index
    for i in range(k + 1):
        ptr[i] = 0
  
    minrange = 10**9
          
    while(1):    
          
            # for mainting the index of list 
            # containing the minimum element
        minind = -1
        minval = 10**9
        maxval = -10**9
        flag = 0
  
        #iterating over all the list
        for i in range(k):
              
                # if every element of list[i] is 
                # traversed then break the loop
            if(ptr[i] == n):
                flag = 1    
                break
  
            # find minimum value among all the list 
            # elements pointing by the ptr[] array 
            if(ptr[i] < n and arr[i][ptr[i]] < minval):
                minind = i # update the index of the list
                minval = arr[i][ptr[i]]
              
            # find maximum value among all the 
            # list elements pointing by the ptr[] array
            if(ptr[i] < n and arr[i][ptr[i]] > maxval):
                maxval = arr[i][ptr[i]]
              
          
  
        # if any list exhaust we will 
        # not get any better answer ,
        # so break the while loop
        if(flag):
            break
  
        ptr[minind] += 1
  
        # updating the minrange
        if((maxval-minval) < minrange):
            minel = minval
            maxel = maxval
            minrange = maxel - minel
      
    print("The smallest range is [", minel, maxel,"]")
  
# Driver code
arr= [
    [4, 7, 9, 12, 15],
    [0, 8, 10, 14, 20],
    [6, 12, 16, 30, 50]
    ]
  
k = len(arr)
  
findSmallestRange(arr, N, k)
  
# This code is contributed by mohit kumar

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program to finds out smallest
// range that includes elements from
// each of the given sorted lists.
using System;
  
class GFG
  
    static int N = 5; 
  
    // array for storing the current index of list i 
    static int []ptr = new int[501]; 
  
    // This function takes an k sorted 
    // lists in the form of 2D array as
    // an argument. It finds out smallest range 
    // that includes elements from each of the k lists. 
    static void findSmallestRange(int [,]arr, 
                                int n, int k)
    
        int i, minval, maxval, minrange, 
        minel = 0, maxel = 0, flag, minind; 
  
        //initializing to 0 index; 
        for (i = 0; i <= k; i++) 
        
            ptr[i] = 0; 
        
  
        minrange = int.MaxValue; 
  
        while (true
        
            // for mainting the index of 
            // list containing the minimum element 
            minind = -1; 
            minval = int.MaxValue; 
            maxval = int.MinValue; 
            flag = 0; 
  
            //iterating over all the list 
            for (i = 0; i < k; i++) 
            
                // if every element of list[i] 
                // is traversed then break the loop 
                if (ptr[i] == n)
                
                    flag = 1; 
                    break
                
                  
                // find minimum value among all the 
                // list elements pointing by the ptr[] array 
                if (ptr[i] < n && arr[i,ptr[i]] < minval) 
                
                    minind = i; // update the index of the list 
                    minval = arr[i,ptr[i]]; 
                
                  
                // find maximum value among all the
                // list elements pointing by the ptr[] array 
                if (ptr[i] < n && arr[i,ptr[i]] > maxval)
                
                    maxval = arr[i,ptr[i]]; 
                
            
  
            // if any list exhaust we will 
            // not get any better answer ,
            // so break the while loop 
            if (flag == 1)
            
                break
            
  
            ptr[minind]++; 
  
            // updating the minrange 
            if ((maxval - minval) < minrange) 
            
                minel = minval; 
                maxel = maxval; 
                minrange = maxel - minel; 
            
        
        Console.WriteLine("The smallest range is"
                           "[{0} , {1}]\n", minel, maxel); 
    
  
    // Driver code 
    public static void Main(String[] args) 
    
  
        int [,]arr = { 
            {4, 7, 9, 12, 15}, 
            {0, 8, 10, 14, 20}, 
            {6, 12, 16, 30, 50} 
        }; 
  
        int k = arr.GetLength(0); 
  
        findSmallestRange(arr, N, k); 
    
  
// This code has been contributed by 29AjayKumar

chevron_right



Output :

The smallest range is [6 8]

Time complexity : O(n2 k)

A Better efficient approach is to use min heap. Below are the steps –

  1. Create a min heap of size k and insert first elements of all k lists into the heap.
  2. Maintain two variables min and max to store minimum and maximum values present in the heap at any point. Note min will always contain value of the root of the heap.
  3. Repeat following steps
    • Get minimum element from heap (minimum is always at root) and compute the range.
    • Replace heap root with next element of the list from which the min element is extracted. After replacing the root, heapify the tree. Update max if next element is greater. If the list doesn’t have any more elements, break the loop.

Below is C++ implementation of above approach –

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to finds out smallest range that includes
// elements from each of the given sorted lists.
#include<iostream>
#include<limits.h>
using namespace std;
  
#define N 5
  
// A min heap node
struct MinHeapNode
{
    int element; // The element to be stored
    int i; // index of the list from which the element is taken
    int j; // index of the next element to be picked from list
};
  
// Prototype of a utility function to swap two min heap nodes
void swap(MinHeapNode *x, MinHeapNode *y);
  
// A class for Min Heap
class MinHeap
{
    MinHeapNode *harr; // pointer to array of elements in heap
    int heap_size; // size of min heap
public:
    // Constructor: creates a min heap of given size
    MinHeap(MinHeapNode a[], int size);
  
    // to heapify a subtree with root at given index
    void MinHeapify(int );
  
    // to get index of left child of node at index i
    int left(int i) { return (2*i + 1); }
  
    // to get index of right child of node at index i
    int right(int i) { return (2*i + 2); }
  
    // to get the root
    MinHeapNode getMin() { return harr[0]; }
  
    // to replace root with new node x and heapify() new root
    void replaceMin(MinHeapNode x) { harr[0] = x; MinHeapify(0); }
};
  
// Constructor: Builds a heap from a given array a[] of given size
MinHeap::MinHeap(MinHeapNode a[], int size)
{
    heap_size = size;
    harr = a; // store address of array
    int i = (heap_size - 1)/2;
    while (i >= 0)
    {
        MinHeapify(i);
        i--;
    }
}
  
// A recursive method to heapify a subtree with root at
// given index. This method assumes that the subtrees
// are already heapified
void MinHeap::MinHeapify(int i)
{
    int l = left(i);
    int r = right(i);
    int smallest = i;
    if (l < heap_size &&
        harr[l].element < harr[i].element)
        smallest = l;
    if (r < heap_size &&
        harr[r].element < harr[smallest].element)
        smallest = r;
    if (smallest != i)
    {
        swap(harr[i], harr[smallest]);
        MinHeapify(smallest);
    }
}
  
// This function takes an k sorted lists in the form of
// 2D array as an argument. It finds out smallest range
// that includes elements from each of the k lists.
void findSmallestRange(int arr[][N], int k)
{
    // Create a min heap with k heap nodes. Every heap node
    // has first element of an list
    int range = INT_MAX;
    int min = INT_MAX, max = INT_MIN;
    int start, end;
  
    MinHeapNode *harr = new MinHeapNode[k];
    for (int i = 0; i < k; i++)
    {
        harr[i].element = arr[i][0]; // Store the first element
        harr[i].i = i; // index of list
        harr[i].j = 1; // Index of next element to be stored
                       // from list
  
        // store max element
        if (harr[i].element > max)
            max = harr[i].element;
    }
  
    MinHeap hp(harr, k); // Create the heap
  
    // Now one by one get the minimum element from min
    // heap and replace it with next element of its list
    while (1)
    {
        // Get the minimum element and store it in output
        MinHeapNode root = hp.getMin();
  
        // update min
        min = hp.getMin().element;
  
        // update range
        if (range > max - min + 1)
        {
            range = max - min + 1;
            start = min;
            end = max;
        }
  
        // Find the next element that will replace current
        // root of heap. The next element belongs to same
        // list as the current root.
        if (root.j < N)
        {
            root.element = arr[root.i][root.j];
            root.j += 1;
  
            // update max element
            if (root.element > max)
                max = root.element;
        }
  
        // break if we have reached end of any list
        else break;
  
        // Replace root with next element of list
        hp.replaceMin(root);
    }
  
    cout << "The smallest range is " << "["
         << start << " " << end << "]" << endl;;
}
  
// Driver program to test above functions
int main()
{
    int arr[][N] = {
                    {4, 7, 9, 12, 15},
                    {0, 8, 10, 14, 20},
                    {6, 12, 16, 30, 50}
                    };
    int k = sizeof(arr)/sizeof(arr[0]);
  
    findSmallestRange(arr, k);
  
    return 0;
}

chevron_right


Output :

The smallest range is [6 8]


Time Complexity:
The while loop inside findSmallestRange() function can run maximum n*k times. In every iteration of loop, we call heapify which takes O(Logk) time. Therefore, the time complexity is O(nk Logk).

This article is contributed by Aditya Goel. If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above



My Personal Notes arrow_drop_up



Article Tags :
Practice Tags :


10


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.