给定一个由n个整数组成的数组A,我想找到选择有序三胞胎的方法。例如。
A = [1, 2, 1, 1]
different ways are (1, 2, 1), (1, 1, 1) and (2, 1, 1)
so the answer will be 3.
for A = [2, 2, 1, 2, 2]
different ways are (1, 2, 2), (2, 1, 2), (2, 2, 1) and (2, 2, 2)
so the answer will be 4 in this case
如果所有数字都是唯一的,那么我想出了一个循环
f(n) = f(n-1) + ((n-1) * (n-2))/2
where f(3) = 1 and f(2) = f(1) = 0
重复数字时遇到麻烦。这需要在O(n)时间和O(n)空间中解决。
答案 0 :(得分:1)
对于大小为 idx 的数组,唯一,有序集的数量的动态编程关系为:
DP [组的大小] [idx] = DP [组的大小] [idx-1] + DP [组的大小-1] [idx-1]-DP [组的大小-1] [last_idx [ A [idx]-1]
因此,要从 idx 元素数组计算大小为LEN的有序唯一集合的数量:
之所以有用,是因为在遍历数组时,我们总是在计数唯一集合。对唯一集合进行计数是基于先前唯一集合的元素计数。
因此,从大小为1的组开始,然后再做大小2,然后是大小3,依此类推。
对于恒定大小LEN的唯一,有序集,我的函数占用O(LEN * N)内存和O(LEN * N)时间。您应该能够重用DP阵列以将内存减少到一个与LEN,O(constant * N)无关的常数。
这是功能。
static int answer(int[] A) {
// This example is for 0 <= A[i] <= 9. For an array of arbitrary integers, use a proper
// HashMap instead of an array as a HashMap. Alternatively, one could compress the input array
// down to distinct, consecutive numbers. Either way max memory of the last_idx array is O(n).
// This is left as an exercise to the reader.
final int MAX_INT_DIGIT = 10;
final int SUBSEQUENCE_LENGTH = 3;
int n = A.length;
int[][] dp = new int[SUBSEQUENCE_LENGTH][n];
int[] last_idx = new int[MAX_INT_DIGIT];
Arrays.fill(last_idx, -1);
// Init dp[0] which gives the number of distinct sets of length 1 ending at index i
dp[0][0] = 1;
last_idx[A[0]] = 0;
for (int i = 1; i < n; i++) {
if (last_idx[A[i]] == -1) {
dp[0][i] = dp[0][i - 1] + 1;
} else {
dp[0][i] = dp[0][i - 1];
}
last_idx[A[i]] = i;
}
for (int ss_len = 1; ss_len < SUBSEQUENCE_LENGTH; ss_len++) {
Arrays.fill(last_idx, -1);
last_idx[A[0]] = 0;
for (int i = 1; i < n; i++) {
if (last_idx[A[i]] <= 0) {
dp[ss_len][i] = dp[ss_len][i - 1] + dp[ss_len-1][i - 1];
} else {
dp[ss_len][i] = dp[ss_len][i - 1] + dp[ss_len-1][i - 1] - dp[ss_len-1][last_idx[A[i]] - 1];
}
last_idx[A[i]] = (i);
}
}
return dp[SUBSEQUENCE_LENGTH-1][n - 1];
}
对于[3 1 1 3 8 0 5 8 9 0],我得到的答案是62。