Given a wooden stick of length n
units. The stick is labelled from 0
to n
. For example, a stick of length 6 is labelled as follows:
Given an integer array cuts
where cuts[i]
denotes a position you should perform a cut at.
You should perform the cuts in order, you can change the order of the cuts as you wish.
The cost of one cut is the length of the stick to be cut, the total cost is the sum of costs of all cuts. When you cut a stick, it will be split into two smaller sticks (i.e. the sum of their lengths is the length of the stick before the cut). Please refer to the first example for a better explanation.
Return the minimum total cost of the cuts.
Example 1:
Input: n = 7, cuts = [1,3,4,5]
Output: 16
Explanation: Using cuts order = [1, 3, 4, 5] as in the input leads to the following scenario:
The first cut is done to a rod of length 7 so the cost is 7. The second cut is done to a rod of length 6 (i.e. the second part of the first cut), the third is done to a rod of length 4 and the last cut is to a rod of length 3. The total cost is 7 + 6 + 4 + 3 = 20.
Rearranging the cuts to be [3, 5, 1, 4] for example will lead to a scenario with total cost = 16 (as shown in the example photo 7 + 4 + 3 + 2 = 16).
思路:注意start,end是代表list里面的index;也是计算区间的范围;加入0,n是为了后面更好的算长度,直接减就可以了;如果长度是1,已经不能分割了,所以为0;不能割,也就没有cost;
class Solution {
public int minCost(int n, int[] cuts) {
List<Integer> list = new ArrayList<Integer>();
list.add(0); list.add(n); // 加入0,n是为了后面更好的算长度,直接减就可以了;
for(int cut: cuts) {
list.add(cut);
}
Collections.sort(list);
int[][] cache = new int[list.size()][list.size()];
return dfs(list, 0, list.size() - 1 , cache);
}
// start, end 是代表 list里面的index;也是计算区间的范围;
private int dfs(List<Integer> list, int start, int end, int[][] cache) {
if(start + 1 >= end) { // 如果长度是1,已经不能分割了,所以为0;不能割,也就没有cost;
return 0;
}
if(cache[start][end] > 0) {
return cache[start][end];
}
int value = Integer.MAX_VALUE;
for(int k = start + 1; k < end; k++) {
// 左边 + 右边 + cost;
value = Math.min(value, dfs(list, start, k, cache) + dfs(list, k, end, cache)
+ list.get(end) - list.get(start));
}
cache[start][end] = value;
return cache[start][end];
}
}
思路2:bottom up,也可以算的,这里的dp[i][j]就是纯粹是下标index的意义,所以dp[i][k] + dp[k][j] + list.get(j) - list.get(i); 为了直接用cuts数组算出木头长度,可以加入0和n,然后这样就用list.get(j) - list.get(i)来算长度,区间型dp,就是先算小的区间,那么除了用len来算,那么也可以从右往左计算,先算区间小的,然后算区间大的;
class Solution {
public int minCost(int n, int[] cuts) {
List<Integer> list = new ArrayList<Integer>();
//加入0和n,是为了直接用cuts数组元素的大小相减,直接算木头的长度;
list.add(0); list.add(n);
for(int cut: cuts) {
list.add(cut);
}
Collections.sort(list);
int[][] dp = new int[list.size()][list.size()];
// 计算顺序,从右往左计算;先算区间小的,然后算区间大的,所以从右往左计算;
for(int i = list.size() - 1; i >= 0; i--) {
for(int j = i + 1; j < list.size(); j++) {
for(int k = i + 1; k < j; k++) {
dp[i][j] = Math.min(dp[i][j] == 0 ? Integer.MAX_VALUE : dp[i][j],
dp[i][k] + dp[k][j] + list.get(j) - list.get(i));
}
}
}
return dp[0][list.size() - 1];
}
}