Minimum Difficulty of a Job Schedule — Hard Problem & Solution
Jobs must be done in order over exactly d days, with at least one job each day.
- Difficulty: Hard
- Topics: Arrays, Dynamic Programming
- Asked at: Amazon, Google, Adobe
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
Jobs must be done in order over exactly d days, with at least one job each day. A day's difficulty is the maximum difficulty among the jobs done that day, and the schedule's difficulty is the sum over the days.
Return the minimum possible schedule difficulty, or -1 if there are fewer jobs than days.
Example 1
Input: jobDifficulty = [6,5,4,3,2,1], d = 2
Output: 7
Explanation: Day 1 takes the first five jobs (difficulty 6), day 2 takes the last (difficulty 1).
Example 2
Input: jobDifficulty = [9,9,9], d = 4
Output: -1
Explanation: Not enough jobs to fill four days.
Example 3
Input: jobDifficulty = [1,1,1], d = 3
Output: 3
Constraints
1 <= jobDifficulty.length <= 3000 <= jobDifficulty[i] <= 10001 <= d <= 10
How to solve Minimum Difficulty of a Job Schedule
A partition DP. The only choice is where each day's block starts, and sweeping that start backwards lets the block's maximum be maintained incrementally instead of recomputed.
Approach
- Return
-1immediately when there are fewer jobs than days. dp[day][i]is the minimum difficulty of scheduling the firstijobs indaydays;dp[0][0] = 0.- For each
i, walkjfromidown today, growing the running maximum ofjobDifficulty[j-1 … i-1], and takedp[day-1][j-1] + max. - The answer is
dp[d][n].
Why it works
Because jobs cannot be reordered, every schedule is a partition into d contiguous non-empty blocks — so enumerating the last block's start covers all of them. Sweeping j downwards means each new j only extends the block leftwards by one job, so the maximum updates in constant time and the inner loop stays linear.
Complexity
- Time —
O(d · n²) - Space —
O(n)
Pitfalls
- Each day needs at least one job, which is what the
j >= daybound enforces. - Recomputing the block maximum from scratch makes the inner loop quadratic and the whole thing
O(d · n³). - A greedy split by equal totals is wrong — the objective is a sum of maxima, not of sums.
Reference solution
Python
from typing import List
def minDifficulty(jobDifficulty: List[int], d: int) -> int:
n = len(jobDifficulty)
if n < d:
return -1
INF = 10 ** 9
prev = [INF] * (n + 1)
prev[0] = 0
for day in range(1, d + 1):
cur = [INF] * (n + 1)
for i in range(day, n + 1):
mx = 0
for j in range(i, day - 1, -1):
mx = max(mx, jobDifficulty[j - 1])
if prev[j - 1] < INF:
cur[i] = min(cur[i], prev[j - 1] + mx)
prev = cur
return prev[n]JavaScript
var minDifficulty = function(jobDifficulty, d) {
var INF = 1000000000;
var n = jobDifficulty.length;
if (n < d) return -1;
var prev = [], t;
for (t = 0; t <= n; t++) prev.push(INF);
prev[0] = 0;
for (var day = 1; day <= d; day++) {
var cur = [];
for (t = 0; t <= n; t++) cur.push(INF);
for (var i = day; i <= n; i++) {
var mx = 0;
for (var j = i; j >= day; j--) {
if (jobDifficulty[j - 1] > mx) mx = jobDifficulty[j - 1];
if (prev[j - 1] < INF && prev[j - 1] + mx < cur[i]) cur[i] = prev[j - 1] + mx;
}
}
prev = cur;
}
return prev[n];
};Also on the editorial tab: C, C#, C++, Go, Java, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.