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.

247 lines
6.3 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 class47;
// 整型数组arr长度为n(3 <= n <= 10^4),最初每个数字是<=200的正数且满足如下条件
// 1. 0位置的要求arr[0]<=arr[1]
// 2. n-1位置的要求arr[n-1]<=arr[n-2]
// 3. 中间i位置的要求arr[i]<=max(arr[i-1],arr[i+1])
// 但是在arr有些数字丢失了比如k位置的数字之前是正数丢失之后k位置的数字为0
// 请你根据上述条件计算可能有多少种不同的arr可以满足以上条件
// 比如 [6,0,9] 只有还原成 [6,9,9]满足全部三个条件所以返回1种即[6,9,9]达标
public class Code02_RestoreWays {
public static int ways0(int[] arr) {
return process0(arr, 0);
}
public static int process0(int[] arr, int index) {
if (index == arr.length) {
return isValid(arr) ? 1 : 0;
} else {
if (arr[index] != 0) {
return process0(arr, index + 1);
} else {
int ways = 0;
for (int v = 1; v < 201; v++) {
arr[index] = v;
ways += process0(arr, index + 1);
}
arr[index] = 0;
return ways;
}
}
}
public static boolean isValid(int[] arr) {
if (arr[0] > arr[1]) {
return false;
}
if (arr[arr.length - 1] > arr[arr.length - 2]) {
return false;
}
for (int i = 1; i < arr.length - 1; i++) {
if (arr[i] > Math.max(arr[i - 1], arr[i + 1])) {
return false;
}
}
return true;
}
public static int ways1(int[] arr) {
int N = arr.length;
if (arr[N - 1] != 0) {
return process1(arr, N - 1, arr[N - 1], 2);
} else {
int ways = 0;
for (int v = 1; v < 201; v++) {
ways += process1(arr, N - 1, v, 2);
}
return ways;
}
}
// 如果i位置的数字变成了v,
// 并且arr[i]和arr[i+1]的关系为s
// s==0代表arr[i] < arr[i+1] 右大
// s==1代表arr[i] == arr[i+1] 右=当前
// s==2代表arr[i] > arr[i+1] 右小
// 返回0...i范围上有多少种有效的转化方式
public static int process1(int[] arr, int i, int v, int s) {
if (i == 0) { // 0...i 只剩一个数了0...0
return ((s == 0 || s == 1) && (arr[0] == 0 || v == arr[0])) ? 1 : 0;
}
// i > 0
if (arr[i] != 0 && v != arr[i]) {
return 0;
}
// i>0 ,并且, i位置的数真的可以变成V
int ways = 0;
if (s == 0 || s == 1) { // [i] -> V <= [i+1]
for (int pre = 1; pre < 201; pre++) {
ways += process1(arr, i - 1, pre, pre < v ? 0 : (pre == v ? 1 : 2));
}
} else { // ? 当前 > 右 当前 <= max{左,右}
for (int pre = v; pre < 201; pre++) {
ways += process1(arr, i - 1, pre, pre == v ? 1 : 2);
}
}
return ways;
}
public static int zuo(int[] arr, int i, int v, int s) {
if (i == 0) { // 0...i 只剩一个数了0...0
return ((s == 0 || s == 1) && (arr[0] == 0 || v == arr[0])) ? 1 : 0;
}
// i > 0
if (arr[i] != 0 && v != arr[i]) {
return 0;
}
// i>0 ,并且, i位置的数真的可以变成V
int ways = 0;
if (s == 0 || s == 1) { // [i] -> V <= [i+1]
for (int pre = 1; pre < v; pre++) {
ways += zuo(arr, i - 1, pre, 0);
}
}
ways += zuo(arr, i - 1, v, 1);
for (int pre = v + 1; pre < 201; pre++) {
ways += zuo(arr, i - 1, pre, 2);
}
return ways;
}
public static int ways2(int[] arr) {
int N = arr.length;
int[][][] dp = new int[N][201][3];
if (arr[0] != 0) {
dp[0][arr[0]][0] = 1;
dp[0][arr[0]][1] = 1;
} else {
for (int v = 1; v < 201; v++) {
dp[0][v][0] = 1;
dp[0][v][1] = 1;
}
}
for (int i = 1; i < N; i++) {
for (int v = 1; v < 201; v++) {
for (int s = 0; s < 3; s++) {
if (arr[i] == 0 || v == arr[i]) {
if (s == 0 || s == 1) {
for (int pre = 1; pre < v; pre++) {
dp[i][v][s] += dp[i - 1][pre][0];
}
}
dp[i][v][s] += dp[i - 1][v][1];
for (int pre = v + 1; pre < 201; pre++) {
dp[i][v][s] += dp[i - 1][pre][2];
}
}
}
}
}
if (arr[N - 1] != 0) {
return dp[N - 1][arr[N - 1]][2];
} else {
int ways = 0;
for (int v = 1; v < 201; v++) {
ways += dp[N - 1][v][2];
}
return ways;
}
}
public static int ways3(int[] arr) {
int N = arr.length;
int[][][] dp = new int[N][201][3];
if (arr[0] != 0) {
dp[0][arr[0]][0] = 1;
dp[0][arr[0]][1] = 1;
} else {
for (int v = 1; v < 201; v++) {
dp[0][v][0] = 1;
dp[0][v][1] = 1;
}
}
int[][] presum = new int[201][3];
for (int v = 1; v < 201; v++) {
for (int s = 0; s < 3; s++) {
presum[v][s] = presum[v - 1][s] + dp[0][v][s];
}
}
for (int i = 1; i < N; i++) {
for (int v = 1; v < 201; v++) {
for (int s = 0; s < 3; s++) {
if (arr[i] == 0 || v == arr[i]) {
if (s == 0 || s == 1) {
dp[i][v][s] += sum(1, v - 1, 0, presum);
}
dp[i][v][s] += dp[i - 1][v][1];
dp[i][v][s] += sum(v + 1, 200, 2, presum);
}
}
}
for (int v = 1; v < 201; v++) {
for (int s = 0; s < 3; s++) {
presum[v][s] = presum[v - 1][s] + dp[i][v][s];
}
}
}
if (arr[N - 1] != 0) {
return dp[N - 1][arr[N - 1]][2];
} else {
return sum(1, 200, 2, presum);
}
}
public static int sum(int begin, int end, int relation, int[][] presum) {
return presum[end][relation] - presum[begin - 1][relation];
}
// for test
public static int[] generateRandomArray(int len) {
int[] ans = new int[len];
for (int i = 0; i < ans.length; i++) {
if (Math.random() < 0.5) {
ans[i] = 0;
} else {
ans[i] = (int) (Math.random() * 200) + 1;
}
}
return ans;
}
// for test
public static void printArray(int[] arr) {
System.out.println("arr size : " + arr.length);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int len = 4;
int testTime = 15;
System.out.println("功能测试开始");
for (int i = 0; i < testTime; i++) {
int N = (int) (Math.random() * len) + 2;
int[] arr = generateRandomArray(N);
int ans0 = ways0(arr);
int ans1 = ways1(arr);
int ans2 = ways2(arr);
int ans3 = ways3(arr);
if (ans0 != ans1 || ans2 != ans3 || ans0 != ans2) {
System.out.println("Oops!");
}
}
System.out.println("功能测试结束");
System.out.println("===========");
int N = 100000;
int[] arr = generateRandomArray(N);
long begin = System.currentTimeMillis();
ways3(arr);
long end = System.currentTimeMillis();
System.out.println("run time : " + (end - begin) + " ms");
}
}