Leetcode 1335. Minimum Difficulty of a Job Schedule

Problem Explanation

The problem requires us to schedule a list of jobs in a certain number of days. Each job has a given difficulty, and jobs are dependent - meaning, to work on a particular job, you must have completed all previous jobs. The difficulty of a job schedule is calculated as the sum of difficulties for each day, with each day's difficulty equal to the highest difficulty job done on that day. If it's impossible to find a valid schedule that fulfills all conditions, return -1.

The task is to identify the schedule with the minimum total difficulty.

Problem Approach

To solve this, we can use dynamic programming with a 2D array dp[][] where dp[i][j] is used to represent the minimum difficulty to schedule the first i jobs in j days. We start with filling dp[0][0] with 0, which denotes the scenario of scheduling 0 jobs in 0 days. And fill the rest of dp array with a large value (INT_MAX/2 in this case because there can be additions later and we don't want to have an integer overflow).

Next, we run two loop iterations:

  • The outer loop "i", where we consider the first i jobs.
  • The inner loop "j", where we iterate backwards from "i-1", considering scenarios of incorporating jobs into the current day’s work schedule.

Both these loops are nested inside another loop "k" which runs over the days. It goes from 1 to "d".

Inside the innermost loop, we keep track of the maximum difficulty job through the variable maxDifficulty, and then calculate the current day’s minimum difficulty which will be the minimum of dp[i][k] and dp[j][k-1] + maxDifficulty. Here, dp[j][k-1] + maxDifficulty represents the total difficulty of the previous day plus the maximum difficulty of the job we are considering on the current day.

Finally, we return dp[n][d] which contains the minimum difficulty of scheduling n jobs in d days.

Through an Example

Consider the job difficulties are [6,5,4,3,2,1] and d is 2.

We can initially finish the first 5 jobs, and the maximum difficulty for these jobs is 6 (from the first job). Then, we can finish the last job on the second day with difficulty 1. So, the total difficulty is 6 + 1 = 7

The condition that we have to finish at least one job a day is fulfilled as well, hence the result is 7.

Solutions

Python Solution

1
2python
3class Solution:
4    def minDifficulty(self, jobDifficulty: List[int], d: int) -> int:
5        if len(jobDifficulty) < d:
6            return -1
7
8        n = len(jobDifficulty)
9        dp = [[float('inf')] * d + [0] for _ in range(n+1)]
10        jobDifficulty = [0] + jobDifficulty
11
12        for i in range(1, n + 1):
13            for j in range(1, min(i, d) + 1):
14                max_d = 0
15                for k in range(i, j-1, -1):
16                    max_d = max(max_d, jobDifficulty[k])
17                    dp[i][j] = min(dp[i][j], dp[k-1][j-1] + max_d)
18        return dp[-1][d]

Java Solution

1
2java
3class Solution {
4    public int minDifficulty(int[] jobDifficulty, int d) {
5        int n = jobDifficulty.length;
6        if (n < d)
7            return -1;
8
9        int[][] dp = new int[n+1][d+1];
10        for (int[] arr : dp) 
11            Arrays.fill(arr, Integer.MAX_VALUE / 2);
12        dp[0][0] = 0;
13
14        for (int i = 1; i <= n; ++i)
15            for (int k = 1; k <= d; ++k) {
16                int maxDifficulty = 0;
17                for (int j = i - 1; j >= k - 1; --j) {
18                    maxDifficulty = Math.max(maxDifficulty, jobDifficulty[j]);
19                    dp[i][k] = Math.min(dp[i][k], dp[j][k - 1] + maxDifficulty);
20                }
21            }
22
23        return dp[n][d];
24    }
25}

JavaScript Solution

1
2javascript
3var minDifficulty = function (jobDifficulty, d) {
4    let n = jobDifficulty.length;
5    if (n < d) return -1;
6
7    let dp = Array.from(Array(n + 1), () => new Array(d + 1).fill(Infinity));
8    dp[0][0] = 0;
9
10    for(let i=1; i<=n; i++) {
11        for(let j=1; j<=i && j<=d; j++) {
12            let temp = 0;
13            for(let k=i-1; k>=j-1; k--) {
14                temp = Math.max(temp, jobDifficulty[k]);
15                dp[i][j] = Math.min(dp[i][j], dp[k][j-1] + temp);
16            }
17        }
18    }
19    return dp[n][d];
20};

C++ Solution

1
2cpp
3class Solution {
4public:
5  int minDifficulty(vector<int>& jobDifficulty, int d) {
6    const int n = jobDifficulty.size();
7    if (n < d)
8      return -1;
9
10    vector<vector<int>> dp(n + 1, vector<int>(d + 1, INT_MAX / 2));
11    dp[0][0] = 0;
12
13    for (int i = 1; i <= n; ++i)
14      for (int k = 1; k <= d; ++k) {
15        int maxDifficulty = 0;
16        for (int j = i - 1; j >= k - 1; --j) {
17          maxDifficulty = max(maxDifficulty, jobDifficulty[j]);
18          dp[i][k] = min(dp[i][k], dp[j][k - 1] + maxDifficulty);
19        }
20      }
21
22    return dp[n][d];
23  }
24};

C# Solution

1
2csharp
3public class Solution {
4    public int MinDifficulty(int[] jobDifficulty, int d) {
5        int n = jobDifficulty.Length;
6        if (n < d)
7            return -1;
8
9        int[,] dp = new int[n+1, d+1];
10        
11        for(int i=0; i<=n; i++)
12            for(int j=0; j<=d; j++)
13                dp[i, j] = int.MaxValue/2;
14        
15        dp[0,0] = 0;
16
17        for (int i = 1; i <= n; ++i)
18            for (int k = 1; k <= d; ++k) {
19                int maxDifficulty = 0;
20                for (int j = i - 1; j >= k - 1; --j) {
21                    maxDifficulty = Math.Max(maxDifficulty, jobDifficulty[j]);
22                    dp[i,k] = Math.Min(dp[i,k], dp[j,k-1] + maxDifficulty);
23                }
24            }
25
26        return dp[n,d];
27    }
28}

Each of these solutions works on the same principle as explained, but translated into their respective languages.In all of these solutions, the algorithm uses a dynamic programming approach to iterating over the job difficulties and days. It fills a 2D dp array that keeps track of the minimum difficulty for each day and job scenario. It updates the difficulty with the current day's highest job difficulty. If there are not enough jobs for the scheduled days, it returns -1 to signify it's impossible to schedule the jobs.

However, it's also worth noting that these algorithms have a time complexity of O(n^2 * d) where n is the number of jobs and d the number of days. This is due to the triply nested loop structure where the outer loop runs for n (number of jobs) iterations, the middle loop runs for d (number of days) iterations, and the inner loop runs at most n times. Therefore, while this algorithm provides a correct solution, it might not perform optimally with large inputs.

To improve on this, an option could be to pre-calculate and store the maximum difficulty of the jobs between each pair of indices in the jobDifficulty array. This way, the innermost loop in the algorithm could be removed, reducing the time complexity from cubic to quadratic. However, this improvement would come at the cost of increasing the space complexity.

In conclusion, solution can be characterized as a trade-off between space and time complexity. While the current solutions favor space efficiency using dynamic programming, they have a significant time complexity which makes them less suitable for large-scale problems. A viable alternative approach could be storing pre-calculated maximum difficulties, which reduces time complexity but requires more memory. Therefore, the optimal approach would depend on the specific constraints and requirements.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫