Open In App

Weighted Job Scheduling

Last Updated : 03 Nov, 2025
Comments
Improve
Suggest changes
112 Likes
Like
Report

Given a 2D array jobs[][] of size n × 3, where each row represents a single job with the following details:

  • jobs[i][0] → Start time of the job
  • jobs[i][1] → End time of the job
  • jobs[i][2] → Profit earned by completing the job

Find the maximum profit you can earn by scheduling non-overlapping jobs.

Note: Two jobs are said to be non-overlapping if the end time of one job is less than or equal to the start time of the next job. If a job ends at time X, another job can start exactly at time X.

Examples: 

Input: jobs[][] = [[1, 2, 50],
[3, 5, 20],
[6, 19, 100],
[2, 100, 200]]
Output: 250
Explanation: The first and fourth jobs with the time range [1, 2] and [2, 100] can be chosen to give maximum profit of 50 + 200 = 250.

Input: jobs[][] = [[1, 3, 60],
[2, 5, 50],
[4, 6, 70],
[5, 7, 30]]
Output: 130
Explanation: The first and third jobs with the time range [1, 3] and [4, 6] can be chosen to give maximum profit of 60 + 70 = 130.

[Naive Approach - 1] Using Recursion - O(2n) Time and O(n) Space

The idea is to recursively explore all combinations of job selections to find the maximum profit.

First, sort the jobs normally by their start time. For each job index i, we have two options:

  • Take the current job → Add its profit and recursively move to the next job whose start time is not less than the current job’s end time.
  • Skip the current job → Move to the next job directly.

The recursion explores both possibilities for every job and returns the maximum profit achievable.

C++
//Driver Code Starts
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//Driver Code Ends


// Recursive utility function to find maximum profit
int maxProfitRec(int i, vector<vector<int>> &jobs) {

    // Base case
    if (i >= jobs.size()) return 0;

    // Option 1: Skip the current job
    int skip = maxProfitRec(i + 1, jobs);

    // Option 2: Take the current job
    int next = i + 1;
    while (next < jobs.size() && jobs[next][0] < jobs[i][1]) next++;
    int take = jobs[i][2] + maxProfitRec(next, jobs);

    return max(take, skip);
}

// Function to find maximum profit
int maxProfit(vector<vector<int>> &jobs) {
    sort(jobs.begin(), jobs.end()); 
    return maxProfitRec(0, jobs);
}


//Driver Code Starts
int main() {
    vector<vector<int>> jobs = {
        {1, 2, 50},
        {3, 5, 20},
        {6, 19, 100},
        {2, 100, 200}
    };

    cout << maxProfit(jobs);
    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.Arrays;

class GFG {
//Driver Code Ends


    // Recursive utility function to find maximum profit
    static int maxProfitRec(int i, int[][] jobs) {

        // Base case
        if (i >= jobs.length) return 0;

        // Option 1: Skip the current job
        int skip = maxProfitRec(i + 1, jobs);

        // Option 2: Take the current job
        int next = i + 1;
        while (next < jobs.length && jobs[next][0] < jobs[i][1]) next++;
        int take = jobs[i][2] + maxProfitRec(next, jobs);

        return Math.max(take, skip);
    }

    // Function to find maximum profit
    static int maxProfit(int[][] jobs) {
        Arrays.sort(jobs, (a, b) -> a[0] - b[0]);
        return maxProfitRec(0, jobs);
    }


//Driver Code Starts
    public static void main(String[] args) {
        int[][] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };

        System.out.println(maxProfit(jobs));
    }
}

//Driver Code Ends
Python
# Recursive utility function to find maximum profit
def maxProfitRec(i, jobs):

    # Base case
    if i >= len(jobs):
        return 0

    # Option 1: Skip the current job
    skip = maxProfitRec(i + 1, jobs)

    # Option 2: Take the current job
    next = i + 1
    while next < len(jobs) and jobs[next][0] < jobs[i][1]:
        next += 1
    take = jobs[i][2] + maxProfitRec(next, jobs)

    return max(take, skip)


# Function to find maximum profit
def maxProfit(jobs):
    jobs.sort()
    return maxProfitRec(0, jobs)



#Driver Code Starts
if __name__ == '__main__':
    jobs = [
        [1, 2, 50],
        [3, 5, 20],
        [6, 19, 100],
        [2, 100, 200]
    ]
    
    print(maxProfit(jobs))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG {
//Driver Code Ends


    // Recursive utility function to find maximum profit
    static int maxProfitRec(int i, int[,] jobs) {

        // Base case
        if (i >= jobs.GetLength(0)) return 0;

        // Option 1: Skip the current job
        int skip = maxProfitRec(i + 1, jobs);

        // Option 2: Take the current job
        int next = i + 1;
        while (next < jobs.GetLength(0) && jobs[next, 0] < jobs[i, 1]) next++;
        int take = jobs[i, 2] + maxProfitRec(next, jobs);

        return Math.Max(take, skip);
    }

    // Function to find maximum profit
    static int maxProfit(int[,] jobs) {
        int n = jobs.GetLength(0);
        List<int[]> list = new List<int[]>();
        for (int i = 0; i < n; i++)
            list.Add(new int[] { jobs[i, 0], jobs[i, 1], jobs[i, 2] });

        list.Sort((a, b) => a[0].CompareTo(b[0]));

        int[,] sorted = new int[n, 3];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < 3; j++)
                sorted[i, j] = list[i][j];

        return maxProfitRec(0, sorted);
    }


//Driver Code Starts
    public static void Main() {
        int[,] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };

        Console.WriteLine(maxProfit(jobs));
    }
}

//Driver Code Ends
JavaScript
// Recursive utility function to find maximum profit
function maxProfitRec(i, jobs) {

    // Base case
    if (i >= jobs.length) return 0;

    // Option 1: Skip the current job
    let skip = maxProfitRec(i + 1, jobs);

    // Option 2: Take the current job
    let next = i + 1;
    while (next < jobs.length && jobs[next][0] < jobs[i][1]) next++;
    let take = jobs[i][2] + maxProfitRec(next, jobs);

    return Math.max(take, skip);
}

// Function to find maximum profit
function maxProfit(jobs) {
    jobs.sort((a, b) => a[0] - b[0]);
    return maxProfitRec(0, jobs);
}


// Driver code
//Driver Code Starts
let jobs = [
    [1, 2, 50],
    [3, 5, 20],
    [6, 19, 100],
    [2, 100, 200]
];

console.log(maxProfit(jobs));

//Driver Code Ends

Output
250

The idea is to optimize the recursive solution by finding the next non-overlapping job using binary search instead of a linear scan.

After sorting the jobs by start time, for each job:

  • If we take it, we add its profit and move to the next job whose start time is current job’s end time (found using binary search).
  • If we skip it, we simply move to the next job.

We return the maximum of both choices.

C++
//Driver Code Starts
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//Driver Code Ends


// Utility function to find the next non-overlapping job using binary search
int findNextJob(int i, vector<vector<int>> &jobs) {
    int low = i + 1, high = jobs.size() - 1, ans = jobs.size();
    while (low <= high) {
        int mid = (low + high) / 2;
        if (jobs[mid][0] >= jobs[i][1]) {
            ans = mid;
            high = mid - 1;
        } else
            low = mid + 1;
    }
    return ans;
}

// Recursive utility function to find maximum profit
int maxProfitRec(int i, vector<vector<int>> &jobs) {

    // Base case
    if (i >= jobs.size()) return 0;

    // Skip the current job
    int skip = maxProfitRec(i + 1, jobs);

    // Take the current job
    int next = findNextJob(i, jobs);
    int take = jobs[i][2] + maxProfitRec(next, jobs);

    return max(take, skip);
}

// Function to find maximum profit
int maxProfit(vector<vector<int>> &jobs) {
    sort(jobs.begin(), jobs.end());
    return maxProfitRec(0, jobs);
}


//Driver Code Starts
int main() {
    vector<vector<int>> jobs = {
        {1, 2, 50},
        {3, 5, 20},
        {6, 19, 100},
        {2, 100, 200}
    };

    cout << maxProfit(jobs);
    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.Arrays;

class GFG {
//Driver Code Ends


    // Utility function to find the next non-overlapping job
    static int findNextJob(int i, int[][] jobs) {
        int low = i + 1, high = jobs.length - 1, ans = jobs.length;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (jobs[mid][0] >= jobs[i][1]) {
                ans = mid;
                high = mid - 1;
            } else
                low = mid + 1;
        }
        return ans;
    }

    // Recursive utility function to find maximum profit
    static int maxProfitRec(int i, int[][] jobs) {
        if (i >= jobs.length) return 0;

        int skip = maxProfitRec(i + 1, jobs);
        int next = findNextJob(i, jobs);
        int take = jobs[i][2] + maxProfitRec(next, jobs);

        return Math.max(take, skip);
    }
    
    // Function to find maximum profit
    static int maxProfit(int[][] jobs) {
        Arrays.sort(jobs, (a, b) -> a[0] - b[0]);
        return maxProfitRec(0, jobs);
    }


//Driver Code Starts
    public static void main(String[] args) {
        int[][] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };
        System.out.println(maxProfit(jobs));
    }
}

//Driver Code Ends
Python
# Utility function for binary search
def findNextJob(jobs, i):
    low, high = i + 1, len(jobs) - 1
    while low <= high:
        mid = (low + high) // 2
        if jobs[mid][0] >= jobs[i][1]:
            high = mid - 1
        else:
            low = mid + 1
    return low

# Recursive utility function to find maximum profit
def maxProfitRec(i, jobs):
    # Base case
    if i >= len(jobs):
        return 0

    # Skip current job
    skip = maxProfitRec(i + 1, jobs)

    # Take current job
    next_index = findNextJob(jobs, i)
    take = jobs[i][2] + maxProfitRec(next_index, jobs)

    return max(take, skip)

# Function to find maximum profit
def maxProfit(jobs):
    jobs.sort()
    return maxProfitRec(0, jobs)


if __name__ == '__main__':
#Driver Code Starts
    jobs = [
        [1, 2, 50],
        [3, 5, 20],
        [6, 19, 100],
        [2, 100, 200]
    ]
    
    print(maxProfit(jobs))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG {
//Driver Code Ends

    
    // Utility function for binary search
    static int findNextJob(int[,] jobs, int i, int n) {
        int low = i + 1, high = n - 1;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (jobs[mid, 0] >= jobs[i, 1])
                high = mid - 1;
            else
                low = mid + 1;
        }
        return low;
    }

    // Recursive utility function to find maximum profit
    static int maxProfitRec(int i, int[,] jobs, int n) {
       
        // Base case
        if (i >= n)
            return 0;

        // Skip current job
        int skip = maxProfitRec(i + 1, jobs, n);

        // Take current job
        int nextIndex = findNextJob(jobs, i, n);
        int take = jobs[i, 2] + maxProfitRec(nextIndex, jobs, n);

        return Math.Max(take, skip);
    }

    // Function to find maximum profit
    static int maxProfit(int[,] jobs) {
        int n = jobs.GetLength(0);
        List<int[]> list = new List<int[]>();
        for (int i = 0; i < n; i++)
            list.Add(new int[] { jobs[i, 0], jobs[i, 1], jobs[i, 2] });

        list.Sort((a, b) => a[0].CompareTo(b[0]));

        for (int i = 0; i < n; i++) {
            jobs[i, 0] = list[i][0];
            jobs[i, 1] = list[i][1];
            jobs[i, 2] = list[i][2];
        }

        return maxProfitRec(0, jobs, n);
    }


//Driver Code Starts
    static void Main() {
        int[,] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };

        Console.WriteLine(maxProfit(jobs));
    }
}

//Driver Code Ends
JavaScript
// Utility function for binary search
function findNextJob(jobs, i) {
  let low = i + 1, high = jobs.length - 1;
  while (low <= high) {
    let mid = Math.floor((low + high) / 2);
    if (jobs[mid][0] >= jobs[i][1])
      high = mid - 1;
    else
      low = mid + 1;
  }
  return low;
}

// Recursive utility function to find maximum profit
function maxProfitRec(i, jobs) {
 
  // Base case
  if (i >= jobs.length) return 0;

  // Skip current job
  let skip = maxProfitRec(i + 1, jobs);

  // Take current job
  let next = findNextJob(jobs, i);
  let take = jobs[i][2] + maxProfitRec(next, jobs);

  return Math.max(take, skip);
}

// Function to find maximum profit
function maxProfit(jobs) {
  jobs.sort((a, b) => a[0] - b[0]);
  return maxProfitRec(0, jobs);
}


// Driver code
//Driver Code Starts
const jobs = [
  [1, 2, 50],
  [3, 5, 20],
  [6, 19, 100],
  [2, 100, 200]
];

console.log(maxProfit(jobs));

//Driver Code Ends

Output
250

[Expected Approach - 1] Using Memoization - O(n log(n)) Time and O(n) Space

The idea is to optimize the recursive solution by storing the results of overlapping subproblems.
For each job at index i, we have two choices:

  • Skip the job: Move to the next index i + 1.
  • Take the job: Add its profit and jump to the next non-overlapping job (found using binary search).

To avoid recomputation, we store the maximum profit from index i to the end in a 1D array dp[], where:
dp[i] = max(take, skip).

C++
//Driver Code Starts
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//Driver Code Ends


// Utility function for binary search
int findNextJob(vector<vector<int>> &jobs, int i) {
    int low = i + 1, high = jobs.size() - 1;
    while (low <= high) {
        int mid = (low + high) / 2;
        if (jobs[mid][0] >= jobs[i][1])
            high = mid - 1;
        else
            low = mid + 1;
    }
    return low;
}

// Recursive function with memoization
int maxProfitRec(int i, vector<vector<int>> &jobs, vector<int> &dp) {

    // Base case
    if (i >= jobs.size()) return 0;

    if (dp[i] != -1) return dp[i];

    // Skip current job
    int skip = maxProfitRec(i + 1, jobs, dp);

    // Take current job
    int nextIndex = findNextJob(jobs, i);
    int take = jobs[i][2] + maxProfitRec(nextIndex, jobs, dp);

    return dp[i] = max(take, skip);
}

// Function to find maximum profit
int maxProfit(vector<vector<int>> &jobs) {
    sort(jobs.begin(), jobs.end());
    int n = jobs.size();
    vector<int> dp(n, -1);
    return maxProfitRec(0, jobs, dp);
}


//Driver Code Starts
int main() {
    vector<vector<int>> jobs = {
        {1, 2, 50},
        {3, 5, 20},
        {6, 19, 100},
        {2, 100, 200}
    };

    cout << maxProfit(jobs);
    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.Arrays;

class GFG {
//Driver Code Ends


    // Utility function for binary search
    static int findNextJob(int[][] jobs, int i) {
        int low = i + 1, high = jobs.length - 1;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (jobs[mid][0] >= jobs[i][1])
                high = mid - 1;
            else
                low = mid + 1;
        }
        return low;
    }

    // Recursive function with memoization
    static int maxProfitRec(int i, int[][] jobs, int[] dp) {

        // Base case
        if (i >= jobs.length) return 0;

        if (dp[i] != -1) return dp[i];

        // Skip current job
        int skip = maxProfitRec(i + 1, jobs, dp);

        // Take current job
        int nextIndex = findNextJob(jobs, i);
        int take = jobs[i][2] + maxProfitRec(nextIndex, jobs, dp);

        return dp[i] = Math.max(take, skip);
    }

    // Function to find maximum profit
    static int maxProfit(int[][] jobs) {
        Arrays.sort(jobs, (a, b) -> a[0] - b[0]);
        int n = jobs.length;
        int[] dp = new int[n];
        Arrays.fill(dp, -1);
        return maxProfitRec(0, jobs, dp);
    }


//Driver Code Starts
    public static void main(String[] args) {
        int[][] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };
        System.out.println(maxProfit(jobs));
    }
}

//Driver Code Ends
Python
# Utility function for binary search
def findNextJob(jobs, i):
    low, high = i + 1, len(jobs) - 1
    while low <= high:
        mid = (low + high) // 2
        if jobs[mid][0] >= jobs[i][1]:
            high = mid - 1
        else:
            low = mid + 1
    return low

# Recursive function with memoization
def maxProfitRec(i, jobs, dp):

    # Base case
    if i >= len(jobs):
        return 0

    if dp[i] != -1:
        return dp[i]

    # Skip current job
    skip = maxProfitRec(i + 1, jobs, dp)

    # Take current job
    nextIndex = findNextJob(jobs, i)
    take = jobs[i][2] + maxProfitRec(nextIndex, jobs, dp)

    dp[i] = max(take, skip)
    return dp[i]

# Function to find maximum profit
def maxProfit(jobs):
    jobs.sort()
    n = len(jobs)
    dp = [-1] * n
    return maxProfitRec(0, jobs, dp)


if __name__ == "__main__":
#Driver Code Starts
    jobs = [
        [1, 2, 50],
        [3, 5, 20],
        [6, 19, 100],
        [2, 100, 200]
    ]
    print(maxProfit(jobs))

#Driver Code Ends
C#
//Driver Code Starts
using System;

class GFG {
//Driver Code Ends


    // Utility function for binary search
    static int findNextJob(int[,] jobs, int i, int n) {
        int low = i + 1, high = n - 1;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (jobs[mid, 0] >= jobs[i, 1])
                high = mid - 1;
            else
                low = mid + 1;
        }
        return low;
    }

    // Recursive function with memoization
    static int maxProfitRec(int i, int[,] jobs, int[] dp, int n) {

        // Base case
        if (i >= n) return 0;

        if (dp[i] != -1) return dp[i];

        // Skip current job
        int skip = maxProfitRec(i + 1, jobs, dp, n);

        // Take current job
        int nextIndex = findNextJob(jobs, i, n);
        int take = jobs[i, 2] + maxProfitRec(nextIndex, jobs, dp, n);

        return dp[i] = Math.Max(take, skip);
    }

    // Function to find maximum profit
    static int maxProfit(int[,] jobs) {
        int n = jobs.GetLength(0);

        // Convert to jagged array for sorting
        int[][] jobArr = new int[n][];
        for (int i = 0; i < n; i++)
            jobArr[i] = new int[] { jobs[i, 0], jobs[i, 1], jobs[i, 2] };

        // Sort by start time (O(n log n))
        Array.Sort(jobArr, (a, b) => a[0].CompareTo(b[0]));

        // Copy back to 2D array
        for (int i = 0; i < n; i++) {
            jobs[i, 0] = jobArr[i][0];
            jobs[i, 1] = jobArr[i][1];
            jobs[i, 2] = jobArr[i][2];
        }

        int[] dp = new int[n];
        Array.Fill(dp, -1);
        return maxProfitRec(0, jobs, dp, n);
    }


//Driver Code Starts
    public static void Main() {
        int[,] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };

        Console.WriteLine(maxProfit(jobs));
    }
}

//Driver Code Ends
JavaScript
// Utility function for binary search
function findNextJob(jobs, i) {
    let low = i + 1, high = jobs.length - 1;
    while (low <= high) {
        let mid = Math.floor((low + high) / 2);
        if (jobs[mid][0] >= jobs[i][1])
            high = mid - 1;
        else
            low = mid + 1;
    }
    return low;
}

// Recursive function with memoization
function maxProfitRec(i, jobs, dp) {

    // Base case
    if (i >= jobs.length) return 0;

    if (dp[i] !== -1) return dp[i];

    // Skip current job
    let skip = maxProfitRec(i + 1, jobs, dp);

    // Take current job
    let nextIndex = findNextJob(jobs, i);
    let take = jobs[i][2] + maxProfitRec(nextIndex, jobs, dp);

    dp[i] = Math.max(take, skip);
    return dp[i];
}

// Function to find maximum profit
function maxProfit(jobs) {
    jobs.sort((a, b) => a[0] - b[0]);
    let n = jobs.length;
    let dp = new Array(n).fill(-1);
    return maxProfitRec(0, jobs, dp);
}


// Driver Code
//Driver Code Starts
const jobs = [
    [1, 2, 50],
    [3, 5, 20],
    [6, 19, 100],
    [2, 100, 200]
];

console.log(maxProfit(jobs));

//Driver Code Ends

Output
250

[Expected Approach - 2] Using Tabulation - O(n log(n)) Time and O(n) Space

The idea is to use a bottom-up dynamic programming approach to iteratively compute the maximum profit.

We define:
dp[i] → the maximum profit that can be obtained starting from the i-th job till the last job.

We first sort the jobs by their start time. Then, we fill the dp array from right to left, since the profit for the current job depends on the future jobs.

For each job i:

  • Use binary search to find the next job next whose start time is not less than the end time of job i.
  • Compute two options:
    take = jobs[i][2] + dp[next]    (take current job and add profit from next non-overlapping job)
    skip = dp[i + 1]  (skip current job)
  • dp[i] = max(take, skip)

Finally, dp[0] gives the maximum profit obtainable from the first job.

C++
//Driver Code Starts
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//Driver Code Ends


// Utility function for binary search
int findNextJob(vector<vector<int>> &jobs, int i) {
    int low = i + 1, high = jobs.size() - 1, ans = jobs.size();
    while (low <= high) {
        int mid = (low + high) / 2;
        if (jobs[mid][0] >= jobs[i][1]) {
            ans = mid;
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return ans;
}

// Function to find maximum profit using tabulation
int maxProfit(vector<vector<int>> &jobs) {
    sort(jobs.begin(), jobs.end());

    int n = jobs.size();
    vector<int> dp(n + 1, 0);

    // Build dp table from end
    for (int i = n - 1; i >= 0; i--) {
        int next = findNextJob(jobs, i);
        int take = jobs[i][2] + dp[next];
        int skip = dp[i + 1];
        dp[i] = max(take, skip);
    }

    return dp[0];
}


//Driver Code Starts
int main() {
    vector<vector<int>> jobs = {
        {1, 2, 50},
        {3, 5, 20},
        {6, 19, 100},
        {2, 100, 200}
    };

    cout << maxProfit(jobs);
    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.Arrays;

class GFG {
//Driver Code Ends


    // Utility function for binary search
    static int findNextJob(int[][] jobs, int i) {
        int low = i + 1, high = jobs.length - 1, ans = jobs.length;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (jobs[mid][0] >= jobs[i][1]) {
                ans = mid;
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return ans;
    }

    // Function to find maximum profit using tabulation
    static int maxProfit(int[][] jobs) {
        Arrays.sort(jobs, (a, b) -> a[0] - b[0]);

        int n = jobs.length;
        int[] dp = new int[n + 1];

        // Build dp table from end
        for (int i = n - 1; i >= 0; i--) {
            int next = findNextJob(jobs, i);
            int take = jobs[i][2] + dp[next];
            int skip = dp[i + 1];
            dp[i] = Math.max(take, skip);
        }

        return dp[0];
    }


//Driver Code Starts
    public static void main(String[] args) {
        int[][] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };

        System.out.println(maxProfit(jobs));
    }
}

//Driver Code Ends
Python
# Utility function for binary search
def findNextJob(jobs, i):
    low, high = i + 1, len(jobs) - 1
    ans = len(jobs)
    while low <= high:
        mid = (low + high) // 2
        if jobs[mid][0] >= jobs[i][1]:
            ans = mid
            high = mid - 1
        else:
            low = mid + 1
    return ans

# Function to find maximum profit using tabulation
def maxProfit(jobs):
    jobs.sort()
    n = len(jobs)
    dp = [0] * (n + 1)

    # Build dp table from end
    for i in range(n - 1, -1, -1):
        next = findNextJob(jobs, i)
        take = jobs[i][2] + dp[next]
        skip = dp[i + 1]
        dp[i] = max(take, skip)

    return dp[0]


if __name__ == '__main__':
#Driver Code Starts
    jobs = [
        [1, 2, 50],
        [3, 5, 20],
        [6, 19, 100],
        [2, 100, 200]
    ]
    print(maxProfit(jobs))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG {
//Driver Code Ends

    
    // Utility function for binary search
    static int findNextJob(List<(int, int, int)> jobs, int i) {
        int n = jobs.Count;
        int low = i + 1, high = n - 1, ans = n;
        
        while (low <= high) {
            int mid = (low + high) / 2;
            if (jobs[mid].Item1 >= jobs[i].Item2)
            {
                ans = mid;
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
            }
        }
        return ans;
    }

    // Function to find maximum profit using tabulation
    static int maxProfit(int[,] jobs) {
        int n = jobs.GetLength(0);

        // Convert array to list of tuples for easy sorting
        var jobList = new List<(int, int, int)>();
        for (int i = 0; i < n; i++)
            jobList.Add((jobs[i, 0], jobs[i, 1], jobs[i, 2]));

        // Sort by start time
        jobList.Sort((a, b) => a.Item1.CompareTo(b.Item1));

        int[] dp = new int[n + 1];

        // Build dp table from end
        for (int i = n - 1; i >= 0; i--)
        {
            int next = findNextJob(jobList, i);
            int take = jobList[i].Item3 + dp[next];
            int skip = dp[i + 1];
            dp[i] = Math.Max(take, skip);
        }

        return dp[0];
    }


//Driver Code Starts
    static void Main() {
        int[,] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };

        Console.WriteLine(maxProfit(jobs));
    }
}

//Driver Code Ends
JavaScript
// Utility function for binary search
function findNextJob(jobs, i) {
    let low = i + 1, high = jobs.length - 1, ans = jobs.length;
    while (low <= high) {
        let mid = Math.floor((low + high) / 2);
        if (jobs[mid][0] >= jobs[i][1]) {
            ans = mid;
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return ans;
}

// Function to find maximum profit using tabulation
function maxProfit(jobs) {
    jobs.sort((a, b) => a[0] - b[0]);
    const n = jobs.length;
    const dp = new Array(n + 1).fill(0);

    // Build dp table from end
    for (let i = n - 1; i >= 0; i--) {
        const next = findNextJob(jobs, i);
        const take = jobs[i][2] + dp[next];
        const skip = dp[i + 1];
        dp[i] = Math.max(take, skip);
    }

    return dp[0];
}


// Driver code
//Driver Code Starts
const jobs = [
    [1, 2, 50],
    [3, 5, 20],
    [6, 19, 100],
    [2, 100, 200]
];

console.log(maxProfit(jobs));

//Driver Code Ends

Output
250

[Expected Approach - 3] Using Priority Queue - O(n log(n)) Time and O(n) Space

We first sort all jobs by their start time. Then, we use a min-heap (priority queue) to keep track of jobs based on their end time.

At each step, we process jobs in increasing order of start time and remove from the heap all jobs that end before or at the current job’s start time — because they don’t overlap.
For every removed job, we update the maximum profit so far, since those jobs have already ended and can safely be combined with the current one.

Then we push the current job into the heap with the total profit = current job’s profit + best profit so far.

This works because:

  1. Sorting by start time ensures we always process compatible jobs in order.
  2. The heap efficiently keeps track of the earliest finishing jobs.
  3. When a job ends before the current one starts, it will also not overlap with any future job, so we can finalize its contribution to profit.

In the end, the maximum profit among all jobs in the heap is our answer.

C++
//Driver Code Starts
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
//Driver Code Ends


int maxProfit(vector<vector<int>> &jobs) {

    sort(jobs.begin(), jobs.end());
    
    // Min-heap to store {end time, total profit till now}
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    
    int maxProfit = 0;
    
    for (auto &job : jobs) {
        int start = job[0], end = job[1], profit = job[2];
        
        // Remove jobs that end before current job starts
        while (!pq.empty() && pq.top().first <= start) {
            maxProfit = max(maxProfit, pq.top().second);
            pq.pop();
        }
        
        // Push current job with profit + best profit so far
        pq.push({end, profit + maxProfit});
    }
    
    // Final maximum profit among all chains
    while (!pq.empty()) {
        maxProfit = max(maxProfit, pq.top().second);
        pq.pop();
    }
    
    return maxProfit;
}


//Driver Code Starts
int main() {
    vector<vector<int>> jobs = {
        {1, 2, 50},
        {3, 5, 20},
        {6, 19, 100},
        {2, 100, 200}
    };

    cout << maxProfit(jobs);
    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.Arrays;
import java.util.PriorityQueue;

class GFG {
//Driver Code Ends


    static int maxProfit(int[][] jobs) {

        Arrays.sort(jobs, (a, b) -> a[0] - b[0]);

        // Min-heap to store {end time, total profit till now}
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);

        int maxProfit = 0;

        for (int[] job : jobs) {
            int start = job[0], end = job[1], profit = job[2];

            // Remove jobs that end before current job starts
            while (!pq.isEmpty() && pq.peek()[0] <= start) {
                maxProfit = Math.max(maxProfit, pq.peek()[1]);
                pq.poll();
            }

            // Push current job with profit + best profit so far
            pq.offer(new int[]{end, profit + maxProfit});
        }

        // Final maximum profit among all chains
        while (!pq.isEmpty()) {
            maxProfit = Math.max(maxProfit, pq.peek()[1]);
            pq.poll();
        }

        return maxProfit;
    }


//Driver Code Starts
    public static void main(String[] args) {
        int[][] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };

        System.out.println(maxProfit(jobs));
    }
}

//Driver Code Ends
Python
#Driver Code Starts
import heapq
#Driver Code Ends


def maxProfit(jobs):

    jobs.sort()
    
    # Min-heap to store {end time, total profit till now}
    pq = []
    maxProfit = 0

    for start, end, profit in jobs:

        # Remove jobs that end before current job starts
        while pq and pq[0][0] <= start:
            maxProfit = max(maxProfit, heapq.heappop(pq)[1])

        # Push current job with profit + best profit so far
        heapq.heappush(pq, (end, profit + maxProfit))

    # Final maximum profit among all chains
    while pq:
        maxProfit = max(maxProfit, heapq.heappop(pq)[1])

    return maxProfit


#Driver Code Starts

if __name__ == "__main__":
    jobs = [
        [1, 2, 50],
        [3, 5, 20],
        [6, 19, 100],
        [2, 100, 200]
    ]

    print(maxProfit(jobs))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

// Min-heap class to store (end time, total profit)
class MinHeap
{
    private List<(int, int)> heap = new List<(int, int)>();

    private void Swap(int i, int j)
    {
        var temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }

    private void HeapifyUp()
    {
        int i = heap.Count - 1;
        while (i > 0)
        {
            int parent = (i - 1) / 2;
            if (heap[parent].Item1 <= heap[i].Item1)
                break;
            Swap(i, parent);
            i = parent;
        }
    }

    private void HeapifyDown()
    {
        int i = 0;
        int n = heap.Count;
        while (true)
        {
            int left = 2 * i + 1;
            int right = 2 * i + 2;
            int smallest = i;

            if (left < n && heap[left].Item1 < heap[smallest].Item1)
                smallest = left;
            if (right < n && heap[right].Item1 < heap[smallest].Item1)
                smallest = right;

            if (smallest == i)
                break;

            Swap(i, smallest);
            i = smallest;
        }
    }

    public void Push((int, int) val)
    {
        heap.Add(val);
        HeapifyUp();
    }

    public (int, int) Pop()
    {
        var top = heap[0];
        var end = heap[heap.Count - 1];
        heap.RemoveAt(heap.Count - 1);
        if (heap.Count > 0)
        {
            heap[0] = end;
            HeapifyDown();
        }
        return top;
    }

    public (int, int) Top()
    {
        return heap.Count > 0 ? heap[0] : (int.MaxValue, 0);
    }

    public bool IsEmpty()
    {
        return heap.Count == 0;
    }
}

class GFG {
//Driver Code Ends

    
    // Function to find maximum profit
    static int maxProfit(int[,] jobs) {
        int n = jobs.GetLength(0);
        List<(int, int, int)> list = new List<(int, int, int)>();

        for (int i = 0; i < n; i++)
            list.Add((jobs[i, 0], jobs[i, 1], jobs[i, 2]));

        // Sort jobs by start time
        list.Sort((a, b) => a.Item1.CompareTo(b.Item1));

        // Min-heap to store {end time, total profit till now}
        MinHeap pq = new MinHeap();
        int maxProfit = 0;

        foreach (var job in list) {
            int start = job.Item1, end = job.Item2, profit = job.Item3;

            // Remove jobs that end before current job starts
            while (!pq.IsEmpty() && pq.Top().Item1 <= start) {
                maxProfit = Math.Max(maxProfit, pq.Top().Item2);
                pq.Pop();
            }

            // Push current job with profit + best profit so far
            pq.Push((end, profit + maxProfit));
        }

        // Final maximum profit among all chains
        while (!pq.IsEmpty()) {
            maxProfit = Math.Max(maxProfit, pq.Top().Item2);
            pq.Pop();
        }

        return maxProfit;
    }


//Driver Code Starts
    static void Main() {
        int[,] jobs = {
            {1, 2, 50},
            {3, 5, 20},
            {6, 19, 100},
            {2, 100, 200}
        };

        Console.WriteLine(maxProfit(jobs));
    }
}

//Driver Code Ends
JavaScript
//Driver Code Starts
class MinHeap {
    constructor() {
        this.heap = [];
    }

    // Push element and maintain min-heap property
    push(val) {
        this.heap.push(val);
        this._heapifyUp();
    }

    // Pop smallest element
    pop() {
        if (this.heap.length === 0) return null;
        const top = this.heap[0];
        const end = this.heap.pop();
        if (this.heap.length > 0) {
            this.heap[0] = end;
            this._heapifyDown();
        }
        return top;
    }

    // Peek smallest element
    top() {
        return this.heap.length > 0 ? this.heap[0] : null;
    }

    // Heapify up
    _heapifyUp() {
        let i = this.heap.length - 1;
        while (i > 0) {
            let parent = Math.floor((i - 1) / 2);
            if (this.heap[parent][0] <= this.heap[i][0]) break;
            [this.heap[parent], this.heap[i]] = [this.heap[i], this.heap[parent]];
            i = parent;
        }
    }

    // Heapify down
    _heapifyDown() {
        let i = 0;
        const n = this.heap.length;
        while (true) {
            let left = 2 * i + 1;
            let right = 2 * i + 2;
            let smallest = i;

            if (left < n && this.heap[left][0] < this.heap[smallest][0]) smallest = left;
            if (right < n && this.heap[right][0] < this.heap[smallest][0]) smallest = right;

            if (smallest === i) break;
            [this.heap[i], this.heap[smallest]] = [this.heap[smallest], this.heap[i]];
            i = smallest;
        }
    }

    isEmpty() {
        return this.heap.length === 0;
    }
}
//Driver Code Ends


function maxProfit(jobs) {

    jobs.sort((a, b) => a[0] - b[0]);
    
    // Min-heap to store {end time, total profit till now}
    const pq = new MinHeap();
    let maxProfit = 0;

    for (let job of jobs) {
        let [start, end, profit] = job;

        // Remove jobs that end before current job starts
        while (!pq.isEmpty() && pq.top()[0] <= start) {
            maxProfit = Math.max(maxProfit, pq.top()[1]);
            pq.pop();
        }

        // Push current job with profit + best profit so far
        pq.push([end, profit + maxProfit]);
    }

    // Final maximum profit among all chains
    while (!pq.isEmpty()) {
        maxProfit = Math.max(maxProfit, pq.top()[1]);
        pq.pop();
    }

    return maxProfit;
}


//Driver Code Starts
// Driver Code
const jobs = [
    [1, 2, 50],
    [3, 5, 20],
    [6, 19, 100],
    [2, 100, 200]
];

console.log(maxProfit(jobs));

//Driver Code Ends

Output
250



Explore