There is a stone game.At the beginning of the game the player picks n piles of stones in a circle
.
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 1:
Input:
[1,1,4,4]
Output:18
Explanation:
1. Merge second and third piles => [2, 4, 4], score +2
2. Merge the first two piles => [6, 4],score +6
3. Merge the last two piles => [10], score +10
Example 2:
Input:
[1, 1, 1, 1]
Output:8
Explanation:
1. Merge first and second piles => [2, 1, 1], score +2
2. Merge the last two piles => [2, 2],score +2
3. Merge the last two piles => [4], score +4
思路:跟 Stone Game I 类似,有点不一样的地方就是array是可以循环取数的,那么解决方法就是copy另外一个数组,B = A + A, 那么就解决了循环的问题;问题转换为,在B数组中,找到长度为n的,最小的cost;
代码跟I一模一样,唯一的区别就是B数组,跟最后的求min;最后比较所有的n长度有效区间谁最小即可,返回该值
public class Solution {
/**
* @param A: An integer array
* @return: An integer
*/
public int stoneGame2(int[] A) {
if(A == null || A.length == 0) return 0;
int n = A.length;
int[] B = new int[n * 2];
for(int i = 0; i < 2 * n; i++) {
B[i] = A[i % n];
}
int[][] f = new int[2*n][2*n];
for(int i = 0; i < 2*n; i++) {
f[i][i] = 0;
}
// prefix sum;
int[] sum = new int[2*n];
for(int i = 0; i < 2*n; i++) {
sum[i] = i == 0 ? B[0] : sum[i-1] + B[i];
}
for(int len = 2; len <= n; len++) {
for(int i = 0; i + len -1 < 2 * n; i++) {
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] +
(i == 0 ? sum[j] : sum[j] - sum[i-1]));
}
}
}
//最后比较所有的n长度有效区间谁最小即可,返回该值
int res = Integer.MAX_VALUE;
for(int i = 0; i < n; i++) {
res = Math.min(res, f[i][i+n-1]);
}
return res;
}
}
Prefix Sum 数组S也可以用2*n+1来表示,那么Sum[i...j] = S[j+1] - S[i];
因为如下推倒:
// 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 stoneGame2(int[] A) {
if(A == null || A.length == 0) return 0;
int n = A.length;
int[] B = new int[n * 2];
for(int i = 0; i < 2 * n; i++) {
B[i] = A[i % n];
}
int[][] f = new int[2*n][2*n];
for(int i = 0; i < 2*n; i++) {
f[i][i] = 0;
}
// prefix sum;
int[] S = new int[2*n+1];
S[0] = 0;
for(int i = 1; i <=2*n; i++){
S[i] = S[i-1] + B[i-1];
}
for(int len = 2; len <= n; len++) {
for(int i = 0; i + len -1 < 2 * n; i++) {
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]);
}
}
}
//最后比较所有的n长度有效区间谁最小即可,返回该值
int res = Integer.MAX_VALUE;
for(int i = 0; i < n; i++) {
res = Math.min(res, f[i][i+n-1]);
}
return res;
}
}