There is a stone game.At the beginning of the game the player picks n
piles of stones in a line.
The goal is to merge the stones in one pile observing the following rules:
- At each step of the game,the player can merge two adjacent piles to a new pile.
- The score is the number of stones in the new pile.
You are to determine the minimum of the total score.
Example
Example 1:
Input: [3, 4, 3]
Output: 17
Example 2:
Input: [4, 1, 1, 4]
Output: 18
Explanation:
1. Merge second and third piles => [4, 2, 4], score = 2
2. Merge the first two piles => [6, 4],score = 8
3. Merge the last two piles => [10], score = 18
思路:这个题目经典的消去型区间动态规划;f[i][j] 代表区间[i,j]之间能够取得的最小的cost
f[i][j] = for all i < k < j, Math.min(f[i][k] + f[k+1][j] + sum[i,j]);
sum[i,j] 用prefix array O(1) 取得;
消去型动态规划,都是len做为外层循环,里面index i进行枚举,从小的长度一直算到大的长度;
int j = i + len - 1; Sum[i,j] = Sum[j] - Sum[i-1];
如果算区间的话,用S[n+1]比较好算: 如果用S[n+1], 那么
S[j] = A[0] + .. + A[j-1];
S[j+1] = A[0] + ...A[i-1] + A[i]+ ... + A[j];
S[i] = A[0] + ... + A[i-1];
S[j+1] - S[i] = A[i] + .. + A[j];
i, j是A数组里面的i,j,所以后面的式子是成立的;
public class Solution {
/**
* @param A: An integer array
* @return: An integer
*/
public int stoneGame(int[] A) {
if(A == null || A.length == 0) return 0;
int n = A.length;
int[][] f = new int[n][n];
// 初始化special case;
for(int i = 0; i < n; i++) {
f[i][i] = 0;
}
int[] S = new int[n+1];
S[0] = 0; // S[j] = A[0] + .. + A[j-1];
for(int i = 1; i <= n; i++) {
S[i] = S[i-1] + A[i-1];
}
// S[j] = A[0] + .. + A[j-1];
// S[j+1] = A[0] + ...A[i-1] + A[i]+ ... + A[j];
// S[i] = A[0] + ... + A[i-1];
// S[j+1] - S[i] = A[i] + .. + A[j];
// i, j是A数组里面的i,j,所以后面的式子是成立的;
// 所有消去型动态规划,都是用len来做循环,然后枚举起点index i;模板必须记住;
for(int len = 2; len <= n; len++) {
for(int i = 0; i + len - 1 < n; i++) { // 注意index i从0开始;
int j = i + len -1;
f[i][j] = Integer.MAX_VALUE;
for(int k = i; k < j; k++) {
f[i][j] = Math.min(f[i][j], f[i][k] + f[k+1][j] + S[j+1] - S[i]);
}
}
}
return f[0][n-1];
}
}