[lintcode] Stone Game

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:

  1. At each step of the game,the player can merge two adjacent piles to a new pile.
  2. 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];
    }
}

 

你可能感兴趣的:(Dynamic,Programming,PrefixSum)