Open In App

Minimum number of intervals to cover the target interval

Given an array A[] consisting of N intervals and a target interval X, the task is to find the minimum number of intervals from the given array A[] such that they entirely cover the target interval. If there doesn’t exist any such interval then print “-1”.

Examples:



Input: A[] = {{1, 3}, {2, 4}, {2, 10}, {2, 3}, {1, 1}}, X = {1, 10}
Output: 2
Explanation:
From the given 5 intervals, {1, 3} and {2, 10} can be selected. Therefore, the points in the range [1, 3] are covered by the interval {1, 3} and the points in the range [4, 10] are covered by the interval {2, 10}.

Input: A[] = {{2, 6}, {7, 9}, {3, 5}, {6, 10}}, X = {1, 4}
Output: -1
Explanation: There exist no set of intervals in the given array A such that they cover the entire target interval.



Approach: The given problem can be solved by using a Greedy Approach. It can be observed that the most optimal choice of the interval from a point p in the target range is the interval (u, v) such that u <= p and v is the maximum possible. Using this observation, follow the steps below to solve the given problem:

Below is the implementation of the above approach:




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the minimum number
// of intervals in the array A[] to
// cover the entire target interval
int minimizeSegment(vector<pair<int, int> > A,
                    pair<int, int> X)
{
    // Sort the array A[] in increasing
    // order of starting point
    sort(A.begin(), A.end());
 
    // Insert a pair of INT_MAX to
    // prevent going out of bounds
    A.push_back({ INT_MAX, INT_MAX });
 
    // Stores start of current interval
    int start = X.first;
 
    // Stores end of current interval
    int end = X.first - 1;
 
    // Stores the count of intervals
    int cnt = 0;
 
    // Iterate over all the intervals
    for (int i = 0; i < A.size();) {
 
        // If starting point of current
        // index <= start
        if (A[i].first <= start) {
            end = max(A[i++].second, end);
        }
        else {
 
            // Update the value of start
            start = end;
 
            // Increment the value
            // of count
            ++cnt;
 
            // If the target interval is
            // already covered or it is
            // not possible to move
            // then break the loop
            if (A[i].first > end
                || end >= X.second) {
                break;
            }
        }
    }
 
    // If the entire target interval
    // is not covered
    if (end < X.second) {
        return -1;
    }
 
    // Return Answer
    return cnt;
}
 
// Driver Code
int main()
{
    vector<pair<int, int> > A = {
        { 1, 3 }, { 2, 4 }, { 2, 10 }, { 2, 3 }, { 1, 1 }
    };
    pair<int, int> X = { 1, 10 };
    cout << minimizeSegment(A, X);
 
    return 0;
}




// Java program for the above approach
import java.util.ArrayList;
import java.util.Comparator;
 
class GFG
{
 
  static class Pair
  {
    int first;
    int second;
 
    public Pair(int f, int s)
    {
      this.first = f;
      this.second = s;
    }
  }
 
  // Function to find the minimum number
  // of intervals in the array A[] to
  // cover the entire target interval
  public static int minimizeSegment(ArrayList<Pair> A, Pair X)
  {
 
    // Sort the array A[] in increasing
    // order of starting point
    final Comparator<Pair> arrayComparator = new Comparator<GFG.Pair>() {
      @Override
      public int compare(Pair o1, Pair o2) {
        return Integer.compare(o1.first, o2.first);
      }
    };
 
    A.sort(arrayComparator);
 
    // Insert a pair of INT_MAX to
    // prevent going out of bounds
    A.add(new Pair(Integer.MAX_VALUE, Integer.MIN_VALUE));
 
    // Stores start of current interval
    int start = X.first;
 
    // Stores end of current interval
    int end = X.first - 1;
 
    // Stores the count of intervals
    int cnt = 0;
 
    // Iterate over all the intervals
    for (int i = 0; i < A.size();) {
 
      // If starting point of current
      // index <= start
      if (A.get(i).first <= start) {
        end = Math.max(A.get(i++).second, end);
      } else {
 
        // Update the value of start
        start = end;
 
        // Increment the value
        // of count
        ++cnt;
 
        // If the target interval is
        // already covered or it is
        // not possible to move
        // then break the loop
        if (A.get(i).first > end
            || end >= X.second) {
          break;
        }
      }
    }
 
    // If the entire target interval
    // is not covered
    if (end < X.second) {
      return -1;
    }
 
    // Return Answer
    return cnt;
  }
 
  // Driver Code
  public static void main(String args[]) {
    ArrayList<Pair> A = new ArrayList<Pair>();
    A.add(new Pair(1, 3));
    A.add(new Pair(2, 4));
    A.add(new Pair(2, 10));
    A.add(new Pair(2, 3));
    A.add(new Pair(1, 1));
    Pair X = new Pair(1, 10);
    System.out.println(minimizeSegment(A, X));
  }
}
 
// This code is contributed by saurabh_jaiswal.




# Function to find the minimum number
# of intervals in the array A[] to
# cover the entire target interval
 
 
def minimizeSegment(A, X):
    # Sort the array A[] in increasing
    # order of starting point
    A.sort()
 
    # Insert a pair of (float('inf'), float('inf'))
    # to prevent going out of bounds
    A.append((float('inf'), float('inf')))
 
    # Stores start of current interval
    start = X[0]
 
    # Stores end of current interval
    end = X[0] - 1
 
    # Stores the count of intervals
    cnt = 0
 
    # Iterate over all the intervals
    i = 0
    while i < len(A):
 
        # If starting point of current
        # index <= start
        if A[i][0] <= start:
            end = max(A[i][1], end)
            i += 1
        else:
 
            # Update the value of start
            start = end
 
            # Increment the value
            # of count
            cnt += 1
 
            # If the target interval is
            # already covered or it is
            # not possible to move
            # then break the loop
            if A[i][0] > end or end >= X[1]:
                break
 
    # If the entire target interval
    # is not covered
    if end < X[1]:
        return -1
 
    # Return Answer
    return cnt
 
 
# Driver Code
A = [
    (1, 3), (2, 4), (2, 10), (2, 3), (1, 1)
]
X = (1, 10)
print(minimizeSegment(A, X))




// C# program for the above approach
using System;
using System.Collections.Generic;
 
public class GFG
{
 
  public class Pair
  {
    public int first;
    public int second;
 
    public Pair(int f, int s) {
      this.first = f;
      this.second = s;
    }
  }
 
  // Function to find the minimum number
  // of intervals in the array []A to
  // cover the entire target interval
  public static int minimizeSegment(List<Pair> A, Pair X) {
 
    // Sort the array []A in increasing
    // order of starting point
 
    A.Sort((a,b)=>a.first-b.first);
 
    // Insert a pair of INT_MAX to
    // prevent going out of bounds
    A.Add(new Pair(int.MaxValue, int.MinValue));
 
    // Stores start of current interval
    int start = X.first;
 
    // Stores end of current interval
    int end = X.first - 1;
 
    // Stores the count of intervals
    int cnt = 0;
 
    // Iterate over all the intervals
    for (int i = 0; i < A.Count;) {
 
      // If starting point of current
      // index <= start
      if (A[i].first <= start) {
        end = Math.Max(A[i++].second, end);
      } else {
 
        // Update the value of start
        start = end;
 
        // Increment the value
        // of count
        ++cnt;
 
        // If the target interval is
        // already covered or it is
        // not possible to move
        // then break the loop
        if (A[i].first > end || end >= X.second) {
          break;
        }
      }
    }
 
    // If the entire target interval
    // is not covered
    if (end < X.second) {
      return -1;
    }
 
    // Return Answer
    return cnt;
  }
 
  // Driver Code
  public static void Main(String []args) {
    List<Pair> A = new List<Pair>();
    A.Add(new Pair(1, 3));
    A.Add(new Pair(2, 4));
    A.Add(new Pair(2, 10));
    A.Add(new Pair(2, 3));
    A.Add(new Pair(1, 1));
    Pair X = new Pair(1, 10);
    Console.WriteLine(minimizeSegment(A, X));
  }
}
 
// This code is contributed by Rajput-Ji




<script>
        // JavaScript Program to implement
        // the above approach
 
        // Function to find the minimum number
        // of intervals in the array A[] to
        // cover the entire target interval
        function minimizeSegment(A,
            X)
           {
         
            // Sort the array A[] in increasing
            // order of starting point
            A.sort(function (a, b) { return a.first - b.first; })
 
            // Insert a pair of INT_MAX to
            // prevent going out of bounds
            A.push({ first: Number.MAX_VALUE, second: Number.MAX_VALUE });
 
            // Stores start of current interval
            let start = X.first;
 
            // Stores end of current interval
            let end = X.first - 1;
 
            // Stores the count of intervals
            let cnt = 0;
 
            // Iterate over all the intervals
            for (let i = 0; i < A.length;) {
 
                // If starting point of current
                // index <= start
                if (A[i].first <= start) {
                    end = Math.max(A[i++].second, end);
                }
                else {
 
                    // Update the value of start
                    start = end;
 
                    // Increment the value
                    // of count
                    ++cnt;
 
                    // If the target interval is
                    // already covered or it is
                    // not possible to move
                    // then break the loop
                    if (A[i].first > end
                        || end >= X.second) {
                        break;
                    }
                }
            }
 
            // If the entire target interval
            // is not covered
            if (end < X.second) {
                return -1;
            }
 
            // Return Answer
            return cnt;
        }
 
        // Driver Code
        let A = [{ first: 1, second: 3 },
        { first: 2, second: 4 },
        { first: 2, second: 10 },
        { first: 2, second: 3 },
        { first: 1, second: 1 }
        ];
        let X = { first: 1, second: 10 };
        document.write(minimizeSegment(A, X));
 
     // This code is contributed by Potta Lokesh
 
    </script>

Output
2





Time Complexity: O(N*log N)
Auxiliary Space: O(1)

Efficient Approach:

The idea is similar to Minimum number of jumps to reach end. The tricky part is how to find the starting point to just cover the `target.first`. Basically, it is a Greedy question. We can use the “sweep line” like method to build an auxiliary array to mimic the Jump Game.

Implement the following steps to solve the problem:

  1.    Initialize variables minVal to INT_MAX and maxVal to 0.
  2.    Iterate over each interval i in A:
    • Update minVal to the minimum of minVal and i.start.
    • Update maxVal to the maximum of maxVal and i.end.
  3.    Create a count array count of size (maxVal – minVal + 1) and initialize all elements to 0.
  4.    Iterate over each interval i in A:
    • Compute the index in the count array as i.start – minVal.
    • Update count[i.start – minVal] to the maximum of count[i.start – minVal] and (i.end – i.start).
  5.    Initialize variables reach and maxReach to 0.
  6.    Compute the indices in the count array for the target interval as targetStart = X.first – minVal and targetEnd = X.second – minVal.
  7.    Initialize a variable i to 0.
  8.    Iterate while i is less than or equal to targetStart:
    • If i + count[i] is less than targetStart, continue to the next iteration.
    • Update reach to the maximum of reach and i + count[i].
    • Increment i by 1.
  9.    Initialize a variable res to 1.
  10.    Continue iterating while i is less than the size of the count array:
    • If reach is greater than or equal to targetEnd, break out of the loop.
    • Update maxReach to the maximum of maxReach and i + count[i].
    • If reach is less than or equal to i:
      • Update reach to maxReach.
      • Increment res by 1.
    • Increment i by 1.
  11.    If reach is greater than or equal to targetEnd, return res, otherwise return -1.

Below is the implementation of the approach:




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the minimum number
// of intervals in the array A[] to
// cover the entire target interval
int minimizeSegment(vector<pair<int, int>> A, pair<int, int> X) {
    // Check if the input vector is empty
    if (A.empty())
        return 0;
 
    // Find the minimum and maximum values
    int minVal = INT_MAX;
    int maxVal = 0;
    for (auto i : A) {
        minVal = min(minVal, i.first);
        maxVal = max(maxVal, i.second);
    }
 
    // Create a count array to store the length
    // of intervals starting at each index
    vector<int> count(maxVal - minVal + 1, 0);
    for (auto i : A) {
        count[i.first - minVal] = max(count[i.first - minVal], i.second - i.first);
    }
 
    // Initialize variables for tracking reach
    int reach = 0;
    int maxReach = 0;
    int targetStart = X.first - minVal;
    int targetEnd = X.second - minVal;
    int i = 0;
 
    // Iterate until reaching the target start
    for (; i <= targetStart; i++) {
        if (i + count[i] < targetStart)
            continue;
        reach = max(reach, i + count[i]);
    }
 
    // Initialize result and continue iteration
    int res = 1;
    for (; i < count.size(); i++) {
        if (reach >= targetEnd)
            break;
        maxReach = max(maxReach, i + count[i]);
        if (reach <= i) {
            reach = maxReach;
            res++;
        }
    }
 
    // Check if the target interval is covered
    return reach >= targetEnd ? res : -1;
}
 
int main() {
    // Input intervals and target interval
    vector<pair<int, int>> A = {
        {1, 3}, {2, 4}, {2, 10}, {2, 3}, {1, 1}
    };
    pair<int, int> X = {1, 10};
 
    // Find the minimum number of intervals
    // to cover the target interval
    int result = minimizeSegment(A, X);
    cout << result << endl;
 
    return 0;
}
 
// This code is contributed by Chandramani Kumar




import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 
public class Main {
 
    // Function to find the minimum number of intervals to
    // cover the target interval
    public static int
    minimizeSegment(List<SimpleEntry<Integer, Integer> > A,
                    SimpleEntry<Integer, Integer> X)
    {
        // Check if the input list is empty
        if (A.isEmpty())
            return 0;
 
        // Find the minimum and maximum values
        int minVal = Integer.MAX_VALUE;
        int maxVal = 0;
        for (SimpleEntry<Integer, Integer> interval : A) {
            minVal = Math.min(minVal, interval.getKey());
            maxVal = Math.max(maxVal, interval.getValue());
        }
 
        // Create a list to store the length of intervals
        // starting at each index
        List<Integer> count = new ArrayList<>(
            Collections.nCopies(maxVal - minVal + 1, 0));
        for (SimpleEntry<Integer, Integer> interval : A) {
            count.set(interval.getKey() - minVal,
                      Math.max(count.get(interval.getKey()
                                         - minVal),
                               interval.getValue()
                                   - interval.getKey()));
        }
 
        // Initialize variables for tracking reach
        int reach = 0;
        int maxReach = 0;
        int targetStart = X.getKey() - minVal;
        int targetEnd = X.getValue() - minVal;
        int i = 0;
 
        // Iterate until reaching the target start
        for (; i <= targetStart; i++) {
            if (i + count.get(i) < targetStart)
                continue;
            reach = Math.max(reach, i + count.get(i));
        }
 
        // Initialize result and continue iteration
        int res = 1;
        for (; i < count.size(); i++) {
            if (reach >= targetEnd)
                break;
            maxReach = Math.max(maxReach, i + count.get(i));
            if (reach <= i) {
                reach = maxReach;
                res++;
            }
        }
 
        // Check if the target interval is covered
        return reach >= targetEnd ? res : -1;
    }
 
    public static void main(String[] args)
    {
        // Input intervals and target interval
        List<SimpleEntry<Integer, Integer> > A
            = new ArrayList<>();
        A.add(new SimpleEntry<>(1, 3));
        A.add(new SimpleEntry<>(2, 4));
        A.add(new SimpleEntry<>(2, 10));
        A.add(new SimpleEntry<>(2, 3));
        A.add(new SimpleEntry<>(1, 1));
        SimpleEntry<Integer, Integer> X
            = new SimpleEntry<>(1, 10);
 
        // Find the minimum number of intervals to cover the
        // target interval
        int result = minimizeSegment(A, X);
        System.out.println(result);
    }
}




# Function to find the minimum number
# of intervals in the array A[] to
# cover the entire target interval
def minimizeSegment(A, X):
    # Check if the A is empty
    if not A:
        return 0
    #Find minimum and maximum value
    minVal = float('inf')
    maxVal = 0
    for i in A:
        minVal = min(minVal, i[0])
        maxVal = max(maxVal, i[1])
    # Create array to store the length
    # of interval starting at each index
    count = [0] * (maxVal - minVal + 1)
    for i in A:
        count[i[0] - minVal] = max(count[i[0] - minVal], i[1] - i[0])
     
    # Initializing variables for tracking reach
    reach = 0
    maxReach = 0
    targetStart = X[0] - minVal
    targetEnd = X[1] - minVal
    i = 0
     
    # Iterate until reaching the target start
    while i <= targetStart:
        if i + count[i] < targetStart:
            i += 1
            continue
        reach = max(reach, i + count[i])
        i += 1
     
    # Initialize result and continue iteration
    res = 1
    while i < len(count):
        if reach >= targetEnd:
            break
        maxReach = max(maxReach, i + count[i])
        if reach <= i:
            reach = maxReach
            res += 1
        i += 1
    # check if the target interval is convered.
    return res if reach >= targetEnd else -1
 
# Input intervals and target interval
A = [
    (1, 3), (2, 4), (2, 10), (2, 3), (1, 1)
]
X = (1, 10)
result = minimizeSegment(A, X)
print(result)




using System;
using System.Collections.Generic;
using System.Linq;
 
class Program
{
    // Function to find the minimum number
    // of intervals in the list A to
    // cover the entire target interval
    static int MinimizeSegment(List<Tuple<int, int>> A, Tuple<int, int> X)
    {
        // Check if the input list is empty
        if (A.Count == 0)
            return 0;
 
        // Find the minimum and maximum values
        int minVal = int.MaxValue;
        int maxVal = 0;
        foreach (var interval in A)
        {
            minVal = Math.Min(minVal, interval.Item1);
            maxVal = Math.Max(maxVal, interval.Item2);
        }
 
        // Create a count array to store the length
        // of intervals starting at each index
        List<int> count = new List<int>(maxVal - minVal + 1);
        count.AddRange(Enumerable.Repeat(0, maxVal - minVal + 1));
        foreach (var interval in A)
        {
            count[interval.Item1 - minVal] = Math.Max(count[interval.Item1 - minVal], interval.Item2 - interval.Item1);
        }
 
        // Initialize variables for tracking reach
        int reach = 0;
        int maxReach = 0;
        int targetStart = X.Item1 - minVal;
        int targetEnd = X.Item2 - minVal;
        int i = 0;
 
        // Iterate until reaching the target start
        for (; i <= targetStart; i++)
        {
            if (i + count[i] < targetStart)
                continue;
            reach = Math.Max(reach, i + count[i]);
        }
 
        // Initialize result and continue iteration
        int res = 1;
        for (; i < count.Count; i++)
        {
            if (reach >= targetEnd)
                break;
            maxReach = Math.Max(maxReach, i + count[i]);
            if (reach <= i)
            {
                reach = maxReach;
                res++;
            }
        }
 
        // Check if the target interval is covered
        return reach >= targetEnd ? res : -1;
    }
 
    static void Main(string[] args)
    {
        // Input intervals and target interval
        List<Tuple<int, int>> A = new List<Tuple<int, int>>
        {
            Tuple.Create(1, 3), Tuple.Create(2, 4), Tuple.Create(2, 10), Tuple.Create(2, 3), Tuple.Create(1, 1)
        };
        Tuple<int, int> X = Tuple.Create(1, 10);
 
        // Find the minimum number of intervals
        // to cover the target interval
        int result = MinimizeSegment(A, X);
        Console.WriteLine(result);
 
         
        Console.ReadLine();
    }
}




function minimizeSegment(A, X) {
    // Check if the input vector is empty
    if (A.length === 0)
        return 0;
         
    // Find the minimum and maximum values
    let minVal = Infinity;
    let maxVal = 0;
    for (let i = 0; i < A.length; i++) {
        minVal = Math.min(minVal, A[i][0]);
        maxVal = Math.max(maxVal, A[i][1]);
    }
     
    // Create a count array to store the length
    // of intervals starting at each index
    let count = new Array(maxVal - minVal + 1).fill(0);
    for (let i = 0; i < A.length; i++) {
        count[A[i][0] - minVal] = Math.max(count[A[i][0] - minVal], A[i][1] - A[i][0]);
    }
     
    // Initialize variables for tracking reach
    let reach = 0;
    let maxReach = 0;
    let targetStart = X[0] - minVal;
    let targetEnd = X[1] - minVal;
    let i = 0;
     
    // Iterate until reaching the target start
    for (; i <= targetStart; i++) {
        if (i + count[i] < targetStart)
            continue;
        reach = Math.max(reach, i + count[i]);
    }
     
    // Initialize result and continue iteration
    let res = 1;
    for (; i < count.length; i++) {
        if (reach >= targetEnd)
            break;
        maxReach = Math.max(maxReach, i + count[i]);
        if (reach <= i) {
            reach = maxReach;
            res++;
        }
    }
    // Check if the target interval is covered
    return reach >= targetEnd ? res : -1;
}
// Input intervals and target interval
let A = [
    [1, 3], [2, 4], [2, 10], [2, 3], [1, 1]
];
let X = [1, 10];
let result = minimizeSegment(A, X);
console.log(result);

Output
2





Time Complexity: O(N) because single traversal is beeing done whether it is of array A or count.

Auxiliary Space: O(N) as count array has been created.


Article Tags :