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
Solution:This is a interval dp problem. Define dp[n+ 1][n + 1] where dp[i][j] means the minimum score for merging ith and jth stones we can get.
So dp[i][j] = max(dp[i][k] + dp[k + 1][j] + presum[j] - presum[i -1]; where k >= i && k < j
Note the computation order should be in the length.
Code (Java):
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[][] dp = new int[n + 1][n + 1];
int[] preSum = new int[n + 1];
for (int i = 1; i <= n; i++) {
preSum[i] = preSum[i - 1] + A[i - 1];
}
for (int len = 2; len <= n; len++) {
for (int i = 1; i <= n - len + 1 ;i++) {
int j = i + len - 1;
dp[i][j] = Integer.MAX_VALUE;
for (int k = i; k < j; k++) {
dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j] + preSum[j] - preSum[i - 1]);
}
}
}
return dp[1][n];
}
}
public class Solution {
/**
* @param A: An integer array
* @return: An integer
*/
public int stoneGame(int[] A) {
// write your code here
if (A == null || A.length == 0) {
return 0;
}
if (A.length == 1) {
return 0;
}
int n = A.length;
int[][] dp = new int[n][n];
int[] presum = new int[n + 1];
for (int i = 1; i <= n; i++) {
presum[i] = presum[i - 1] + A[i - 1];
}
for (int len = 2; len <= n; len++) {
for (int i = 0; i <= n - len; i++) {
int j = i + len - 1;
dp[i][j] = Integer.MAX_VALUE;
for (int k = i; k < j; k++) {
dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j] + presum[j + 1] - presum[i] );
}
}
}
return dp[0][n - 1];
}
}
Use Memo search:
public class Solution {
/**
* @param A: An integer array
* @return: An integer
*/
public int stoneGame(int[] A) {
// write your code here
if (A == null || A.length == 0) {
return 0;
}
if (A.length == 1) {
return 0;
}
int n = A.length;
int[][] dp = new int[n][n];
int[] presum = new int[n + 1];
for (int i = 1; i <= n; i++) {
presum[i] = presum[i - 1] + A[i - 1];
}
return stoneGameHelper(A, 0, n - 1, dp, presum);
}
private int stoneGameHelper(int[] A, int start, int end, int[][] dp, int[] presum) {
if (start == end) {
return 0;
}
if (dp[start][end] != 0) {
return dp[start][end];
}
int score = Integer.MAX_VALUE;
for (int k = start; k < end; k++) {
int left = stoneGameHelper(A, start, k, dp, presum);
int right = stoneGameHelper(A, k + 1, end, dp, presum);
score = Math.min(score, left + right + presum[end + 1] - presum[start]);
}
dp[start][end] = score;
return score;
}
}
No comments:
Post a Comment