You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
4.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class23;
// 本题测试链接 : https://leetcode.com/problems/minimum-cost-to-merge-stones/
public class Code05_MinimumCostToMergeStones {
// // arr[L...R]一定要整出P份合并的最小代价返回
// public static int f(int[] arr, int K, int L, int R, int P) {
// if(从L到R根本不可能弄出P份) {
// return Integer.MAX_VALUE;
// }
// // 真的有可能的!
// if(P == 1) {
// return L == R ? 0 : (f(arr, K, L, R, K) + 最后一次大合并的代价);
// }
// int ans = Integer.MAX_VALUE;
// // 真的有可能P > 1
// for(int i = L; i < R;i++) {
// // L..i(1份) i+1...R(P-1份)
// int left = f(arr, K, L, i, 1);
// if(left == Integer.MAX_VALUE) {
// continue;
// }
// int right = f(arr, K, i+1,R,P-1);
// if(right == Integer.MAX_VALUE) {
// continue;
// }
// int all = left + right;
// ans = Math.min(ans, all);
// }
// return ans;
// }
public static int mergeStones1(int[] stones, int K) {
int n = stones.length;
if ((n - 1) % (K - 1) > 0) {
return -1;
}
int[] presum = new int[n + 1];
for (int i = 0; i < n; i++) {
presum[i + 1] = presum[i] + stones[i];
}
return process1(0, n - 1, 1, stones, K, presum);
}
// part >= 1
// arr[L..R] 一定要弄出part份返回最低代价
// arr、K、presum前缀累加和数组求i..j的累加和就是O(1)了)
public static int process1(int L, int R, int P, int[] arr, int K, int[] presum) {
if (L == R) { // arr[L..R]
return P == 1 ? 0 : -1;
}
// L ... R 不只一个数
if (P == 1) {
int next = process1(L, R, K, arr, K, presum);
if (next == -1) {
return -1;
} else {
return next + presum[R + 1] - presum[L];
}
} else { // P > 1
int ans = Integer.MAX_VALUE;
// L...mid是第1块剩下的是part-1块
for (int mid = L; mid < R; mid += K - 1) {
// L..mid(一份) mid+1...R(part - 1)
int next1 = process1(L, mid, 1, arr, K, presum);
int next2 = process1(mid + 1, R, P - 1, arr, K, presum);
if (next1 != -1 && next2 != -1) {
ans = Math.min(ans, next1 + next2);
}
}
return ans;
}
}
public static int mergeStones2(int[] stones, int K) {
int n = stones.length;
if ((n - 1) % (K - 1) > 0) { // n个数到底能不能K个相邻的数合并最终变成1个数
return -1;
}
int[] presum = new int[n + 1];
for (int i = 0; i < n; i++) {
presum[i + 1] = presum[i] + stones[i];
}
int[][][] dp = new int[n][n][K + 1];
return process2(0, n - 1, 1, stones, K, presum, dp);
}
public static int process2(int L, int R, int P, int[] arr, int K, int[] presum, int[][][] dp) {
if (dp[L][R][P] != 0) {
return dp[L][R][P];
}
if (L == R) {
return P == 1 ? 0 : -1;
}
if (P == 1) {
int next = process2(L, R, K, arr, K, presum, dp);
if (next == -1) {
dp[L][R][P] = -1;
return -1;
} else {
dp[L][R][P] = next + presum[R + 1] - presum[L];
return next + presum[R + 1] - presum[L];
}
} else {
int ans = Integer.MAX_VALUE;
// i...mid是第1块剩下的是part-1块
for (int mid = L; mid < R; mid += K - 1) {
int next1 = process2(L, mid, 1, arr, K, presum, dp);
int next2 = process2(mid + 1, R, P - 1, arr, K, presum, dp);
if (next1 == -1 || next2 == -1) {
dp[L][R][P] = -1;
return -1;
} else {
ans = Math.min(ans, next1 + next2);
}
}
dp[L][R][P] = ans;
return ans;
}
}
// for test
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) (maxSize * Math.random()) + 1];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) ((maxValue + 1) * Math.random());
}
return arr;
}
// for test
public static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int maxSize = 12;
int maxValue = 100;
System.out.println("Test begin");
for (int testTime = 0; testTime < 100000; testTime++) {
int[] arr = generateRandomArray(maxSize, maxValue);
int K = (int) (Math.random() * 7) + 2;
int ans1 = mergeStones1(arr, K);
int ans2 = mergeStones2(arr, K);
if (ans1 != ans2) {
System.out.println(ans1);
System.out.println(ans2);
}
}
}
}