Minimum Cost to Cut a Stick
Hard · 1-D Dynamic Programming · Explanation and code example
Dynamic Programming (Bottom-Up)
How it works
We can solve this iteratively by building up from smaller segments to larger ones. First, add 0 and n as boundary points to the sorted cuts. Then dp[i][j] represents the minimum cost to cut the segment between cuts[i] and cuts[j]. We fill the table by increasing segment length, since longer segments depend on solutions for shorter ones.
Steps
- Create extended cuts array:
[0] + sorted(cuts) + [n]. - Initialize a 2D DP table with zeros.
- For each segment length from
2tom+1:- For each starting index
i:- Set
j = i + length. - Try each cut point
midbetweeniandj. dp[i][j] = min(cuts[j] - cuts[i] + dp[i][mid] + dp[mid][j]).
- Set
- For each starting index
- Return
dp[0][m + 1].
Complexity
- Time complexity:
O(mlog m + m ^ 3) - Space complexity:
O(m ^ 2)
Where
mis the size of thecutsarray andnis the length of the stick.
Things to watch for
Forgetting to Sort the Cuts Array
The cuts array is not guaranteed to be sorted in the input. Processing cuts in an unsorted order leads to incorrect subproblem definitions because the algorithm assumes cuts are ordered by position when dividing segments.
Not Adding Boundary Points (0 and n)
In the bottom-up DP approach, the segment boundaries 0 and n must be included in the extended cuts array. Without these endpoints, the algorithm cannot properly represent the full stick or calculate costs for segments touching the edges.
Using Wrong Cost Calculation
The cost of a cut equals the length of the current segment being cut, not the position of the cut itself. Confusing cuts[mid] (the cut position) with cuts[j] - cuts[i] (the segment length) produces incorrect results.
Incorrect Base Case Handling
The base case occurs when no cuts exist within a segment, returning cost 0. Returning infinity or failing to detect when i > j in the memoized solution causes the algorithm to miss valid states or compute incorrect minimum values.
State Space Confusion Between Approaches
The recursive solutions using (l, r) positions vs. (i, j) cut indices define different state spaces. Mixing these representations or using position-based states without proper indexing leads to exponential state explosion and memory issues for large stick lengths.
Python code example
from typing import List
class Solution:
def minCost(self, n: int, cuts: List[int]) -> int:
m = len(cuts)
cuts = [0] + sorted(cuts) + [n]
dp = [[0] * (m + 2) for _ in range(m + 2)]
for length in range(2, m + 2):
for i in range(m + 2 - length):
j = i + length
dp[i][j] = float("inf")
for mid in range(i + 1, j):
dp[i][j] = min(
dp[i][j],
cuts[j] - cuts[i] + dp[i][mid] + dp[mid][j]
)
return dp[0][m + 1]
C++ code example
class Solution {
public:
int minCost(int n, vector<int>& cuts) {
int m = cuts.size();
cuts.push_back(0);
cuts.push_back(n);
sort(cuts.begin(), cuts.end());
vector<vector<int>> dp(m + 2, vector<int>(m + 2, 0));
for (int length = 2; length <= m + 1; length++) {
for (int i = 0; i + length <= m + 1; i++) {
int j = i + length;
dp[i][j] = INT_MAX;
for (int mid = i + 1; mid < j; mid++) {
dp[i][j] = min(dp[i][j],
cuts[j] - cuts[i] + dp[i][mid] + dp[mid][j]);
}
}
}
return dp[0][m + 1];
}
};
Source and license
Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.