Given a wooden stick of length n units. The stick is labeled from 0 to n. We are also given an integer array cuts[], where each element cuts[i] represents the position along the stick at which we can make a cut.
Each cut costs the length of the stick being cut, and after every cut, the stick is divided into two smaller sticks. We can perform the cuts in any order, determine the minimum total cost required to perform all cuts.
Examples:
Input: n = 10, cuts[] = [2, 4, 7] Output: 20 Explanation: If we cut the stick in the order [4, 2, 7], it will give the minimum total cost.
In this problem, we have multiple possibilities for where we can make the first cut. Once we cut the stick at a certain position, it divides into two smaller parts and each of those parts again becomes a smaller version of the same problem. Because we have to explore all possible ways of cutting and find the one that gives the minimum total cost, using recursion becomes a very natural and intuitive choice here.
The idea is like this - first, we include 0 and n in the cuts array because these represent the two ends of the stick. This helps define every segment clearly between two valid cut positions. Since the order of cuts matters, and we also need to easily calculate the length of any segment, we sort the cuts array. Sorting allows us to directly find the current stickโs length using the difference (right - left). After sorting, we explore all possible ways to make a cut between left and right. If we make a cut at position cuts[i], the stick splits into two smaller subproblems - one from left to cuts[i] and another from cuts[i] to right. We then solve both subproblems recursively to find their minimum cost.
We will stop the recursion when there are no more possible cuts between left and right, that means when the segment length becomes โค 1. In that case, no further cuts are possible, so the cost is 0.
Output
20
Time Complexity: O(k!), where k is the number of cuts because we explore all possible orders of cuts. Auxiliary Space: O(k) โ due to the recursion stack.
[Expected Approach - 1] Using Memoization (Top Down)
In the recursive approach, we noticed that many subproblems are solved multiple times. For example, the cost to cut a segment [left, right] is computed repeatedly whenever this segment appears in different recursive paths. To avoid this repeated work, we use memoization (DP).
The idea is simple: whenever we compute the minimum cost for a segment [left, right], we store the result in a DP table. We can create a 2D DP table where dp[i][j] represents the minimum cost to cut the stick between the i-th and j-th cut positions. Before performing the recursion for a segment, we check if dp[i][j] has already been computed. If yes, we return it directly; otherwise, we compute and store it. This reduces the exponential recursive solution to a polynomial time solution.
Output
20
Time complexity: O(k3), where k is the number of cuts. Auxiliary Space: O(k2)
[Expected Approach - 2] Using Bottom-Up (Tabulation)
In the memoization approach, we used recursion along with a DP table to store results of subproblems so that we donโt recompute them again and again. Although this reduced the number of repeated calculations, it still relied on recursive calls, which can lead to extra stack usage and overhead. To overcome this, we switch to a completely iterative (bottom-up) method known as Tabulation.
The idea is similar, here instead of making recursive calls, we iteratively build the DP table from smaller segments to larger ones. We start with the smallest possible segments (where no cuts can be made), and for these, the cost is naturally 0. Then, we gradually move to larger segments - at each step, combining the results of smaller parts that have already been computed and stored in the DP table. This ensures that whenever we calculate the cost for a bigger segment, the results of all its sub-segments are readily available. By the end, the DP table contains the minimum cost for every possible segment.
Output
20
Time complexity: O(k3), where k is the number of cuts. Auxiliary Space: O(k2)
Why Space Optimization Is Not Possible in This Problem?
In most Dynamic Programming problems, we can often reduce space complexity by observing that the current state only depends on a limited number of previous states. This allows us to reuse memory - keeping only one or two previous rows instead of the entire DP table. However, in this problem, the dependency pattern is fundamentally different. Each state dp[left][right] represents the minimum cost to cut the stick between cuts[left] and cuts[right]. To compute this value, we must explore all possible cuts between left and right, and for every possible cut position i, we rely on two non-adjacent subproblems โ dp[left][i] and dp[i][right]. This means:
There is no fixed transition direction (like top-down or left-right).
Each state can depend on many scattered intervals that are spread across the DP table.
These dependencies can overlap in unpredictable patterns, making it impossible to safely overwrite previous results.
Because of this complex interval dependency, we cannot discard previously computed values or compress the DP table into fewer rows/columns without losing essential data required for future calculations.