~/DHRUVUpskilling
← board/DSA/merge Intervel/dsa-merge-intervel-04
Revision 1·28 Sept

Employee Free Time

DifficultyHard
Patternmerge Intervel
TrackDSA
tl;dr

You’re given a list containing the schedules of multiple employees. Each person’s schedule is a list of non-overlapping intervals in sorted order. An interval is specified with the start and end time, both being positive integers. Your task is to find the list of finite intervals representing the free time for all the employees.

full write-up

You’re given a list containing the schedules of multiple employees. Each person’s schedule is a list of non-overlapping intervals in sorted order. An interval is specified with the start and end time, both being positive integers. Your task is to find the list of finite intervals representing the free time for all the employees.

Constraints

  • 1 ≤ schedule.length, schedule[i].length ≤ 50
  • 0 ≤ interval.start < interval.end ≤ 10⁸, where interval is any interval in the list of schedules.

Examples

Example 1

Input: schedule = [[[1, 3], [6, 7]], [[2, 4]], [[2, 5], [9, 12]]]

Explanation: Combining all intervals: [1, 3], [6, 7], [2, 4], [2, 5], [9, 12]. Merging overlapping intervals gives busy periods: [1, 5], [6, 7], [9, 12]. The gaps between these busy periods (excluding the very start and end) represent free time.

Output: [[5, 6], [7, 9]]

Example 2

Input: schedule = [[[1, 2], [5, 6]], [[1, 3]], [[4, 10]]]

Explanation: Combining all intervals: [1, 2], [5, 6], [1, 3], [4, 10]. Merging overlapping intervals gives busy periods: [1, 3], [4, 10]. The gap between these busy periods represents free time.

Output: [[3, 4]]

Solution

We'll start by flattering all the intervals provided, after that I'll sort them to combine all the overlapping intervals. Now I'll have busyTime of all the employees, Freetime is gap between all the busytime intervals.

function EmployeeFreetime(intervals){

    let combinedIntervals=[]

    for(let i=0; i<intervals.length; i++){

            combinedIntervals.push(...intervals[i])

    }

let sortedCombinedIntervals=combinedIntervals.sort((a,b)=>a[0]-b[0]);

    let busyTime=[sortedCombinedIntervals[0]];

    for(let i=1; i<sortedCombinedIntervals.length; i++){

    let lastEntry= busyTime[busyTime.length-1];
        if(lastEntry[1]>=sortedCombinedIntervals[i][0]){
            busyTime[busyTime.length-1][1]=Math.max(lastEntry[1], sortedCombinedIntervals[i][1])
        }else{
            busyTime.push(sortedCombinedIntervals[i])
        }

    }

    let freeTime=[];

    for (let i=0; i<busyTime.length; i++){
        if(i+1<busyTime.length){

            let curr=busyTime[i];
            let next = busyTime[i+1];

            freeTime.push([curr[1],next[0]])
        }

    }
    return freeTime
}
console.log(EmployeeFreetime( [
    [[1, 3], [6, 7]], [[2, 4]], [[2, 5], [9, 12]]]))

or Little clean solution

function employeeFreeTime(schedules) {
    // 1. Flatten everyone's intervals into a single array (without mutating originals)
    const allIntervals = schedules.flatMap(employeeIntervals =>
        employeeIntervals.map(([start, end]) => [start, end])
    );

    if (allIntervals.length === 0) return [];

    // 2. Sort intervals by start time
    allIntervals.sort((a, b) => a[0] - b[0]);

    // 3. Merge overlapping/touching intervals into busy blocks
    const mergedBusyTimes = [allIntervals[0]];

    for (let i = 1; i < allIntervals.length; i++) {
        const [start, end] = allIntervals[i];
        const lastMerged = mergedBusyTimes[mergedBusyTimes.length - 1];

        if (start <= lastMerged[1]) {
            // Overlaps with the last merged block -> extend it
            lastMerged[1] = Math.max(lastMerged[1], end);
        } else {
            // No overlap -> start a new busy block
            mergedBusyTimes.push([start, end]);
        }
    }

    // 4. Gaps between consecutive busy blocks are the free time
    const freeTime = [];
    for (let i = 0; i < mergedBusyTimes.length - 1; i++) {
        const currentEnd = mergedBusyTimes[i][1];
        const nextStart = mergedBusyTimes[i + 1][0];
        freeTime.push([currentEnd, nextStart]);
    }

    return freeTime;
}

console.log(employeeFreeTime([
    [[1, 3], [6, 7]],
    [[2, 4]],
    [[2, 5], [9, 12]]
]));
// -> [[5, 6], [7, 9]]