Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maximum sum of the range non-overlapping intervals in a list of Intervals

Someone asked me this question:
You are given a list of intervals. You have to design an algorithm to find the sequence of non-overlapping intervals so that the sum of the range of intervals is maximum.

For Example:
If given intervals are:

["06:00","08:30"],
["09:00","11:00"],
["08:00","09:00"],
["09:00","11:30"],
["10:30","14:00"],
["12:00","14:00"]

Range is maximized when three intervals

[“06:00”, “08:30”],
[“09:00”, “11:30”],
[“12:00”, “14:00”],

are chosen.

Therefore, the answer is 420 (minutes).

like image 973
Black_Hat Avatar asked Dec 21 '22 01:12

Black_Hat


2 Answers

This is a standard interval scheduling problem.
It can be solved by using dynamic programming.

Algorithm
Let there be n intervals. sum[i] stores maximum sum of interval up to interval i in sorted interval array. The algorithm is as follows

Sort the intervals in order of their end timings.
sum[0] = 0
For interval i from 1 to n in sorted array
    j = interval in 1 to i-1 whose endtime is less than beginning time of interval i.
    If j exist, then sum[i] = max(sum[j]+duration[i],sum[i-1])
    else sum[i] = max(duration[i],sum[i-1])

The iteration goes for n steps and in each step, j can be found using binary search, i.e. in log n time. Hence algorithm takes O(n log n) time.

like image 157
Shashwat Kumar Avatar answered Dec 28 '22 05:12

Shashwat Kumar


public int longestNonOverLappingTI(TimeInterval[] tis){
        Arrays.sort(tis);
        int[] mt = new int[tis.length];
        mt[0] = tis[0].getTime();
        for(int j=1;j<tis.length;j++){
            for(int i=0;i<j;i++){
                int x = tis[j].overlaps(tis[i])?tis[j].getTime():mt[i] + tis[j].getTime();
                mt[j]  = Math.max(x,mt[j]);
            }
        }

        return getMax(mt);
    }


public class TimeInterval implements Comparable <TimeInterval> {
    public int start;
    public int end;
    public TimeInterval(int start,int end){
        this.start = start;
        this.end = end;

    }



    public boolean overlaps(TimeInterval that){
          return !(that.end < this.start || this.end < that.start);
    }

    public int getTime(){
        return end - start;
    }
    @Override
    public int compareTo(TimeInterval timeInterval) {
        if(this.end < timeInterval.end)
            return -1;
        else if( this.end > timeInterval.end)
            return 1;
        else{
            //end timeIntervals are same
            if(this.start < timeInterval.start)
                return -1;
            else if(this.start > timeInterval.start)
                return 1;
            else
                return 0;
        }

    }


}

Heres the working code. Basically this runs in O(n^2) because of the two for loops. But as Shashwat said there are ways to make it run in O(n lg n)

like image 27
smk Avatar answered Dec 28 '22 06:12

smk