![]() |
VOOZH | about |
Given an array arr[] and an integer k, where the array represents the boards and each element denotes the length of a board, and k painters are available to paint these boards. Each unit length of a board takes 1 unit of time to paint. Find the minimum time required to paint all the boards such that each painter paints only contiguous sections of the array. A painter can paint boards like [2, 3, 4], [1], or even no board, but cannot paint non-contiguous boards like [2, 4, 5].
Examples:
Input: arr[] = [5, 10, 30, 20, 15], k = 3
Output: 35
Explanation: The most optimal way will be: Painter 1 allocation : [5,10], Painter 2 allocation : [30], Painter 3 allocation : [20, 15], Job will be done when all painters finish i.e. at time = max(5 + 10, 30, 20 + 15) = 35Input: arr[] = [10, 20, 30, 40], k = 2
Output: 60
Explanation: The most optimal way to paint: Painter 1 allocation : [10, 20, 30], Painter 2 allocation : [40], Job will be complete at time = 60
Table of Content
A brute force solution is to consider all possible ways to divide the array into at most k contiguous partitions and calculate the maximum sum for each partitioning. The minimum among all such maximum values is returned as the answer.
The recursive function assigns a continuous segment of boards starting from index curr to the current painter. For each possible partition point, it recursively computes the minimum time required for the remaining boards using the remaining painters.
Recurrence Relation:
Let minTime(curr, k) represent the minimum time to paint the boards from curr to the end with k remaining painters. The recurrence relation is:
- minTime(curr, k) = min {max(sum(curr, i), minTime(i + 1, k - 1))}
Where:
sum(curr, i) is the total time for the current painter to paint boards from index curr to i where i can range from curr to n - k.
minTime(i + 1, k - 1) is the recursive call for the remaining boards and painters.Base Cases:
- No boards left (curr >= n): Return 0, as there’s nothing to paint.
- Only one painter remains (k == 1): Return the sum of remaining boards from curr to n - 1.
- No painters left (k == 0): Return infinity, as it is infeasible to paint remaining boards.
35
If we closely observe the recursive function minTime(), it solves the overlapping subproblems multiple times in different recursive paths, leading to redundant computations. This redundancy can be avoided by applying memoization. Since the state of the recursion is defined by the current index (curr) and the number of remaining painters (k), we use a 2D array of size n x (k+1) to store results. The array is initialized with -1 to indicate uncomputed states, so previously solved subproblems can be reused.
35
The approach is similar to the previous one. Instead of breaking down the problem recursively, we iteratively build up the solution by calculating in bottom-up manner.
We create a 2D array dp, where dp[i][j] represents the minimum time required to paint boards starting from index i to the last board (n-1) using j painters.
The recurrence relation for filling this DP table is as follows:
- dp[i][j] = min over i1 {max(sum(i, i1), dp[i1 + 1][j - 1])}
Where:
- i1 ranges from i to n - j, representing the point where the current painter stops painting (i.e., from i to i1).
- sum(i, i1) represents the total time taken by the current painter to paint the boards from index i to i1. This is calculated using a prefix sum array for efficiency.
- dp[i1 + 1][j - 1] represents the minimum time required to paint the remaining boards from i1 + 1 to n-1 using j - 1 painters.
We take the maximum of sum(i, i1) and dp[i1 + 1][j - 1] because the time taken by the current painter is limited by the maximum time among the painters, and the goal is to minimize the maximum time.
Base Case:
- dp[n][j] = 0 for all j. This represents the scenario where there are no boards left to paint, so the time required is 0, regardless of the number of painters remaining.
- dp[i][1] = sum(i, n-1). This represents the case where only one painter is available, so all remaining boards must be painted by that painter.
35
The idea is to apply binary search on the answer to find the minimum time required to paint all boards using at most k painters.
The search space lies between:
- the maximum board length (minimum possible time), and
- the sum of all board lengths (maximum possible time)
For each mid value, we perform a greedy feasibility check:
- Assign boards sequentially to a painter.
- If the current workload exceeds the allowed time, allocate a new painter.
- Ensure that boards are assigned in continuous sections.
If all boards can be painted using at most k painters, the time is feasible.
The problem exhibits a monotonic property:
- If a time T is sufficient, then any time greater than T will also be sufficient.
- If a time T is not sufficient, then any time smaller than T will also not be sufficient.
This forms a monotonic boolean function, which makes the search space ordered and allows us to efficiently apply binary search to find the minimum feasible time.
Input: arr = [5, 10, 30, 20, 15], k = 3, Search space: low = 30, high = 80
Minimum time to paint all boards = 35
35
Time Complexity: O(n × log(sum(arr))), Binary search is applied over the range from max(arr) to sum(arr), resulting in O(log(sum(arr))) iterations. In each iteration, a greedy feasibility check scans the array once, taking O(n) time.
Auxiliary Space: O(1)