Вот немного другой дубль.Мы можем думать о количестве способов, которыми элемент, m
, может быть k
th в подпоследовательности как сумма всех способов, которыми предыдущее вхождение любого элемента (включая m
) может быть (k-1)
th.Однако, когда мы движемся вправо, единственное необходимое обновление - для m
;остальные суммы остаются постоянными.
Например,
// We want to avoid counting [1,1,1], [1,2,1], etc. twice
[1, 2, 1, 1, 1]
(для удобства выведите массив вертикально)
<- k ->
[1, -> 1: [1, 0, 0]
2, -> 2: [1, 1, 0]
1, -> 1: [1, 2, 1]
1, -> 1: [1, 2, 3]
1] -> 1: [1, 2, 3]
Теперь, если мы добавили еще один элемент, скажем 3,
...
3] -> 3: [1, 2, 3]
// 1 means there is one way
// the element, 3, can be first
// 2 means there are 2 ways
// 3 can be second: sum distinct
// column k[0] = 1 + 1 = 2
// 3 means there are 3 ways
// 3 can be third: sum distinct
// column k[1] = 2 + 1 = 3
Отличная сумма k[2]
столбец:
0 + 3 + 3 = 6 subsequences
[1,2,1], [2,1,1], [1,1,1]
[1,1,3], [2,1,3], [3,2,1]
Отличная сумма для каждого столбца может быть обновлена в O(1)
за итерацию.Суммы k
для текущего элемента (мы обновляем один список для каждого элемента), принимают O(k)
, что в нашем случае равно O(1)
.
Код JavaScript:
function f(A, k){
A.unshift(null);
let sumDistinct = new Array(k + 1).fill(0);
let hash = {};
sumDistinct[0] = 1;
for (let i=1; i<A.length; i++){
let newElement;
if (!hash[A[i]]){
hash[A[i]] = new Array(k + 1).fill(0);
newElement = true;
}
let prev = hash[A[i]].slice();
// The number of ways an element, m, can be k'th
// in the subsequence is the sum of all the ways
// the previous occurence of any element
// (including m) can be (k-1)'th
for (let j=1; j<=k && j<=i; j++)
hash[A[i]][j] = sumDistinct[j - 1];
for (let j=2; j<=k && j<=i; j++)
sumDistinct[j] = sumDistinct[j] - prev[j] + hash[A[i]][j];
if (newElement)
sumDistinct[1] += 1;
console.log(JSON.stringify([A[i], hash[A[i]], sumDistinct]))
}
return sumDistinct[k];
}
var arr = [1, 2, 1, 1, 1, 3, 2, 1];
console.log(f(arr, 3));