n
的排列是一个长度为A
的数组n
,每次包含条目1,2,...,n
。
排列A
的反向下降集是长0-1
的{{1}}数组D
,n-1
如果D[i] = 0
是i+1
i+2
左侧A
以及D[i] = 1
。
示例(n=4
):
[1, 2, 3, 4] [0, 0, 0]
[1, 2, 4, 3] [0, 0, 1]
[1, 3, 4, 2] [0, 1, 0]
[2, 3, 4, 1] [1, 0, 0]
[1, 3, 2, 4] [0, 1, 0]
[2, 3, 1, 4] [1, 0, 0]
[1, 4, 2, 3] [0, 0, 1]
[1, 4, 3, 2] [0, 1, 1]
[2, 4, 3, 1] [1, 0, 1]
[3, 4, 2, 1] [1, 1, 0]
[2, 1, 3, 4] [1, 0, 0]
[3, 1, 2, 4] [0, 1, 0]
[4, 1, 2, 3] [0, 0, 1]
[2, 1, 4, 3] [1, 0, 1]
[3, 1, 4, 2] [0, 1, 0]
[2, 4, 1, 3] [1, 0, 1]
[3, 4, 1, 2] [0, 1, 0]
[3, 2, 1, 4] [1, 1, 0]
[4, 2, 1, 3] [1, 0, 1]
[4, 3, 1, 2] [0, 1, 1]
[3, 2, 4, 1] [1, 1, 0]
[4, 2, 3, 1] [1, 0, 1]
[4, 1, 3, 2] [0, 1, 1]
[4, 3, 2, 1] [1, 1, 1]
计算置换的逆下降集的天真方法是O(n^2)
。我真的更喜欢更快的东西。这是天真的事情
for (int i=0; i<n-1; ++i) {
for (int j=i+1; j<n; ++j) {
if (A[j] == i+2) {
D[i] = 1;
break;
} else if (A[j] = i+1) {
D[i] = 0;
break;
}
}
}
这被称为反向下降,因为如果你采用排列的倒数然后采用通常的下降集,那么它就是你得到的。排列A
的通常下降集是长度为D
的数组n-1
,其中D[i] = 1
如果A[i] > A[i+1]
则为0
。
因此,一个想法是计算置换的倒数,然后在一遍O(n)
中取下降集。但是,我知道采用逆的最佳方法仍然是O(n^2)
,因此不能保存任何内容,但也许有更快的方法。
我用C ++写作,但任何伪代码解决方案都会很棒。
答案 0 :(得分:3)
我认为你计算逆的方法很好,因为这可以在O(n)中完成。
只需将i
的每个值从0循环到n-1并存储E[A[i]]=i
。
这会计算一个数组E
,其中E[j]
给出原始排列中A[i]
的位置。
答案 1 :(得分:1)
这可以在O(n)中完成。
每个D[i]
代表首先看到i+1
或i+2
。因此,对于每个A[i]
,更新D[A[i] - 1]
和D[A[i] - 2]
(仅针对边缘情况更新其中一个),适当地设置元素。
例如[4,1,3,2]
:
4 => D[2] is unset so D[2] := 1
1 => D[0] is unset so D[0] := 0
3 => D[1] is unset so D[1] := 1; D[2] is already set
2 => D[1] is already set; D[0] is already set
D = [0,1,1]
代码:
//Initialize all elements of D to something other than 0 or 1; for example, 2.
for (int i=0; i<n; ++i) {
// edge cases
if (A[i] == 1 && D[0] == 2){
D[0] = 0;
} else if (A[i] == n && D[n - 2] == 2){
D[n - 2] = 1;
// everything else
} else {
if (D[ A[i] - 2 ] == 2){
D[ A[i] - 2 ] = 1;
}
if (D[ A[i] - 1 ] == 2){
D[ A[i] - 1 ] = 0;
}
}
}