Painters Partition Problem
Problem Statement
Given an array of n boards where each board has a certain length, and k painters, such that each painter takes 1 unit of time to paint 1 unit of board. Find the minimum time to paint all boards under the following constraints:
- A painter can only paint contiguous boards
- Each board must be painted by exactly one painter
Constraints:
- 1 ≤ k ≤ n ≤ 10^5
- 1 ≤ boards[i] ≤ 10^5
Example:
- Input:
boards = [10, 20, 30, 40],k = 2 - Output:
60 - Explanation: Painter 1 paints [10, 20, 30] = 60, Painter 2 paints [40] = 40. Max time = 60.
Example 2:
- Input:
boards = [10, 10, 10, 10],k = 2 - Output:
20 - Explanation: Each painter paints 2 boards = 20 time units.
Approach 1: Brute Force (Recursion)
Intuition
Try all possible ways to partition the array into k contiguous parts and find the partition that minimizes the maximum sum.
Algorithm
- Use recursion to place k-1 partition points
- Calculate maximum sum for each partition configuration
- Track the minimum of all maximum sums
public class Solution {
private int minTime = Integer.MAX_VALUE;
private int getSum(int[] boards, int start, int end) {
int sum = 0;
for (int i = start; i <= end; i++) {
sum += boards[i];
}
return sum;
}
private void solve(int[] boards, int idx, int k, int currentMax) {
int n = boards.length;
if (k == 1) {
int sum = getSum(boards, idx, n - 1);
minTime = Math.min(minTime, Math.max(currentMax, sum));
return;
}
for (int i = idx; i <= n - k; i++) {
int sum = getSum(boards, idx, i);
solve(boards, i + 1, k - 1, Math.max(currentMax, sum));
}
}
public int paintersPartition(int[] boards, int k) {
if (k > boards.length) return -1;
minTime = Integer.MAX_VALUE;
solve(boards, 0, k, 0);
return minTime;
}
}Complexity Analysis
- Time Complexity: O(n^k) - Trying all ways to place k-1 partitions
- Space Complexity: O(k) - Recursion stack depth
Approach 2: Binary Search on Answer (Optimal)
Intuition
If we can complete painting with maximum time T, we can also complete with any time > T. This monotonic property allows binary search on the answer.
Key Observations:
- Minimum possible time = max(boards[i]) (each painter gets at least one board)
- Maximum possible time = sum(boards) (one painter does everything)
- For a given time limit, greedily check if k painters are enough
- Binary search to find minimum valid time
Algorithm
- Set low = max(boards), high = sum(boards)
- Binary search on maximum time
- For each mid, check if we can paint with k painters
- If possible, try smaller time; else, increase time
import java.util.*;
public class PaintersPartition {
private boolean canPaint(int[] boards, int k, long maxTime) {
int painters = 1;
long currentTime = 0;
for (int board : boards) {
if (board > maxTime) return false;
if (currentTime + board > maxTime) {
painters++;
currentTime = board;
if (painters > k) return false;
} else {
currentTime += board;
}
}
return true;
}
public long minTime(int[] boards, int k) {
int n = boards.length;
if (k > n) return -1;
long low = 0, high = 0;
for (int board : boards) {
low = Math.max(low, board);
high += board;
}
long result = high;
while (low <= high) {
long mid = low + (high - low) / 2;
if (canPaint(boards, k, mid)) {
result = mid;
high = mid - 1;
} else {
low = mid + 1;
}
}
return result;
}
public static void main(String[] args) {
PaintersPartition pp = new PaintersPartition();
int[] boards = {10, 20, 30, 40};
System.out.println(pp.minTime(boards, 2)); // Output: 60
}
}Dry Run Example
boards = [10, 20, 30, 40], k = 2
low = max(10, 20, 30, 40) = 40
high = 10 + 20 + 30 + 40 = 100
Iteration 1:
mid = 70
canPaint(70)?
Painter 1: 10 + 20 + 30 = 60 ≤ 70, add 40 → 100 > 70
Painter 2: 40 ≤ 70
painters = 2 ≤ k. Return true.
result = 70, high = 69
Iteration 2:
mid = 54
canPaint(54)?
Painter 1: 10 + 20 = 30 ≤ 54, add 30 → 60 > 54
Painter 2: 30 + 40 = 70 > 54
Painter 3: 40 ≤ 54
painters = 3 > k. Return false.
low = 55
Iteration 3:
mid = 62
canPaint(62)?
Painter 1: 10 + 20 + 30 = 60 ≤ 62, add 40 → 100 > 62
Painter 2: 40 ≤ 62
painters = 2 ≤ k. Return true.
result = 62, high = 61
Iteration 4:
mid = 58
canPaint(58)?
Painter 1: 10 + 20 = 30 ≤ 58, add 30 → 60 > 58
Painter 2: 30 + 40 = 70 > 58
Painter 3: 40 ≤ 58
painters = 3 > k. Return false.
low = 59
Iteration 5:
mid = 60
canPaint(60)?
Painter 1: 10 + 20 + 30 = 60 ≤ 60, add 40 → 100 > 60
Painter 2: 40 ≤ 60
painters = 2 ≤ k. Return true.
result = 60, high = 59
low > high, loop ends.
Result: 60
Allocation: [10, 20, 30] = 60, [40] = 40
Maximum time = 60 ✓
Complexity Analysis
- Time Complexity: O(n log(sum))
- Binary search: O(log(sum - max)) iterations
- Each canPaint: O(n)
- Space Complexity: O(1)
Variant: Return the Actual Partition
Similar Problems
| Problem | Description | |---------|-------------| | Book Allocation | Same as painters partition | | Split Array Largest Sum | Minimize maximum sum of k subarrays | | Capacity to Ship | Minimize ship capacity to deliver in D days | | Aggressive Cows | Maximize minimum distance |
Key Takeaways
- Binary Search on Answer: When minimizing maximum (or maximizing minimum), binary search on the answer space
- Monotonic Property: If time T works, all times > T also work
- Greedy Verification: Greedily assign boards to painters and count required painters
- Search Space Bounds: low = max(boards), high = sum(boards)
- Contiguous Constraint: Painters must paint contiguous boards
- Time = Units: Each unit of board takes 1 unit of time
- Pattern Recognition: "Minimize maximum" → Binary Search on Answer