package class_2022_04_3_week; import java.util.Arrays; // 来自腾讯音乐 // 原本数组中都是大于0、小于等于k的数字,是一个单调不减的数组 // 其中可能有相等的数字,总体趋势是递增的 // 但是其中有些位置的数被替换成了0,我们需要求出所有的把0替换的方案数量: // 1)填充的每一个数可以大于等于前一个数,小于等于后一个数 // 2)填充的每一个数不能大于k public class Code03_ValidSortedArrayWays { // 动态规划 public static long ways1(int[] nums, int k) { int n = nums.length; // dp[i][j] : 一共i个格子,随意填,但是不能降序,j种数可以选 long[][] dp = new long[n + 1][k + 1]; for (int i = 1; i <= n; i++) { dp[i][1] = 1; } for (int i = 1; i <= k; i++) { dp[1][i] = i; } for (int i = 2; i <= n; i++) { for (int j = 2; j <= k; j++) { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } long res = 1; for (int i = 0, j = 0; i < nums.length; i++) { if (nums[i] == 0) { j = i + 1; while (j < nums.length && nums[j] == 0) { j++; } int leftValue = i - 1 >= 0 ? nums[i - 1] : 1; int rightValue = j < nums.length ? nums[j] : k; res *= dp[j - i][rightValue - leftValue + 1]; i = j; } } return res; } // 数学方法 // a ~ b范围的数字随便选,可以选重复的数,一共选m个 // 选出有序序列的方案数:C ( m, b - a + m ) public static long ways2(int[] nums, int k) { long res = 1; for (int i = 0, j = 0; i < nums.length; i++) { if (nums[i] == 0) { j = i + 1; while (j < nums.length && nums[j] == 0) { j++; } int leftValue = i - 1 >= 0 ? nums[i - 1] : 1; int rightValue = j < nums.length ? nums[j] : k; int numbers = j - i; res *= c(rightValue - leftValue + numbers, numbers); i = j; } } return res; } // 从一共a个数里,选b个数,方法数是多少 public static long c(int a, int b) { if (a == b) { return 1; } long x = 1; long y = 1; for (int i = b + 1, j = 1; i <= a; i++, j++) { x *= i; y *= j; long gcd = gcd(x, y); x /= gcd; y /= gcd; } return x / y; } public static long gcd(long m, long n) { return n == 0 ? m : gcd(n, m % n); } // 为了测试 public static int[] randomArray(int n, int k) { int[] ans = new int[n]; for (int i = 0; i < n; i++) { ans[i] = (int) (Math.random() * k) + 1; } Arrays.sort(ans); for (int i = 0; i < n; i++) { ans[i] = Math.random() < 0.5 ? 0 : ans[i]; } return ans; } // 为了测试 public static void main(String[] args) { int N = 20; int K = 30; int testTimes = 10000; System.out.println("测试开始"); for (int i = 0; i < testTimes; i++) { int n = (int) (Math.random() * N) + 1; int k = (int) (Math.random() * K) + 1; int[] arr = randomArray(n, k); long ans1 = ways1(arr, k); long ans2 = ways2(arr, k); if (ans1 != ans2) { System.out.println("出错了"); for (int num : arr) { System.out.print(num + " "); } System.out.println(); System.out.println(ans1); System.out.println(ans2); } } System.out.println("测试结束"); } }