Algorithm 如何从n个元素中找到k置换的索引?
我知道,对于大小为Algorithm 如何从n个元素中找到k置换的索引?,algorithm,permutation,Algorithm,Permutation,我知道,对于大小为k的k排列p,由n元素构建,有: P(n, k) = n! / (n - k)! 可能的k-置换。例如: k = 2 n = 4 l = [1, 2, 3, 4] P(n, k) = 4! / (4 - 2)! = 12 1 2 | 2 1 | 3 1 | 4 1 1 3 | 2 3 | 3 2 | 4 2 1 4 | 2 4 | 3 4 | 4 3 k = 3 n = 4 l = [1, 2, 3, 4] P(n, k) = 4! / (4 - 3)! = 24 1
k
的k
排列p
,由n
元素构建,有:
P(n, k) = n! / (n - k)!
可能的k
-置换。例如:
k = 2
n = 4
l = [1, 2, 3, 4]
P(n, k) = 4! / (4 - 2)! = 12
1 2 | 2 1 | 3 1 | 4 1
1 3 | 2 3 | 3 2 | 4 2
1 4 | 2 4 | 3 4 | 4 3
k = 3
n = 4
l = [1, 2, 3, 4]
P(n, k) = 4! / (4 - 3)! = 24
1 2 3 | 2 1 3 | 3 1 2 | 4 1 2
1 2 4 | 2 1 4 | 3 1 4 | 4 1 3
1 3 2 | 2 3 1 | 3 2 1 | 4 2 1
1 3 4 | 2 3 4 | 3 2 4 | 4 2 3
1 4 2 | 2 4 1 | 3 4 1 | 4 3 1
1 4 3 | 2 4 3 | 3 4 2 | 4 3 2
还有一个例子:
k = 2
n = 4
l = [1, 2, 3, 4]
P(n, k) = 4! / (4 - 2)! = 12
1 2 | 2 1 | 3 1 | 4 1
1 3 | 2 3 | 3 2 | 4 2
1 4 | 2 4 | 3 4 | 4 3
k = 3
n = 4
l = [1, 2, 3, 4]
P(n, k) = 4! / (4 - 3)! = 24
1 2 3 | 2 1 3 | 3 1 2 | 4 1 2
1 2 4 | 2 1 4 | 3 1 4 | 4 1 3
1 3 2 | 2 3 1 | 3 2 1 | 4 2 1
1 3 4 | 2 3 4 | 3 2 4 | 4 2 3
1 4 2 | 2 4 1 | 3 4 1 | 4 3 1
1 4 3 | 2 4 3 | 3 4 2 | 4 3 2
那么,我如何找到k
-排列p
的索引呢?考虑排列
按字典顺序生成
编辑:
首先,我可以找到p
所在的“块”,通过p
的第一个元素对块进行寻址。例如,对于p=[3,2,4]
,p
的索引应至少为12(从0到p(n,k)-1计数)
但是,为了找到“块”中的第二个元素,我必须看看剩余的项目是什么,以及它们将位于哪个位置。我的意思是,我最终将处理列表[1,4]
,4将位于位置2,因此简单地使用元素作为键将需要一些额外的操作
我可以使用散列来查找元素并更新它们的位置,但它会给我一个O(n^2)
时间复杂度。有没有可能做得更好
然而,这是蛮力;当然,pos
对排列的结构一无所知。使用(BST)。在开始之前将所有号码存储在其中,并在使用后将其删除。要查找第x个元素,请为每个顶点维护。子树化,然后从树下找到所需的编号。伪代码:
def findXth(x):
curVertex = BST.root
while:
curPosition = curVertex.leftChild.subtreeSize
if curPosition == x: return curVertex.value
elif curPosition > x: curVertex = curVertex.leftChild
elif curPosition < x: curVertex = curVertex.rightChild
def findXth(x):
curVertex=BST.root
而:
curPosition=curVertex.leftChild.subtreeSize
如果curPosition==x:返回curVertex.value
elif curPosition>x:curVertex=curVertex.leftChild
elif curPosition
不要忘记检查顶点是否存在,并删除找到的顶点
整体复杂度将是O(n logn)。给定位置上给定数字的排列数由公式给出
(n位位置)!/(n-k)!其中,数字位置从左侧1开始
要获得给定置换(即其索引)的前置置换数,请将每个数字的公式乘以尚未使用的前置位数,然后将其相加
例1,k=2,n=4,p=[3,4]
第一位数字,3:
(4-1)! / (4-2)! * (未使用的前一位数,2)=6
在第一个排列之前有六个排列,位置1中有3个
第二位数字,4:
(4-2)! / (4-2)! * (未使用的前一位数,2)=2
在第一个排列之前有两个排列,位置2有4
零基索引:6+2=8
例2,k=3,n=4,p=[3,2,4]
第一位数字,3:
(4-1)! / (4-3)! * (未使用的前一位数,2)=12
在第一个排列之前有12个排列,位置1中有3个
第二位数字,2:
(4-2)! / (4-3)! * (未使用的前一位数,1)=2
在第一个排列之前有两个排列,位置2为2
第三位数字,4:
(4-3)! / (4-3)! * (未使用的前一位数,1)=1
在第一个排列之前有一个排列,其位置3中有4
零基索引:12+2+1=15。您可以参考以下函数
/**
* list all k or <=k size permutation of a given list with n unique elements.
* n can be bigger than 64. this function will take O(K^N) time, Bad.
*
* @param uniqueList
* @param permutationSize
* @param permutation
* @param only Only show the permutation of permutationSize,
* else show all permutation of less than or equal to permutationSize.
*/
public static void my_permutationOf(List<Integer> uniqueList, int permutationSize, List<Integer> permutation, boolean only) {
if (permutation == null) {
assert 0 < permutationSize && permutationSize <= uniqueList.size();
permutation = new ArrayList<>(permutationSize);
if (!only) {
System.out.println(Arrays.toString(permutation.toArray()));
}
}
for (int i : uniqueList) {
if (permutation.contains(i)) {
continue;
}
permutation.add(i);
if (!only) {
System.out.println(Arrays.toString(permutation.toArray()));
} else if (permutation.size() == permutationSize) {
System.out.println(Arrays.toString(permutation.toArray()));
}
if (permutation.size() < permutationSize) {
my_permutationOf(uniqueList, permutationSize, permutation, only);
}
permutation.remove(permutation.size() - 1);
}
}
谢谢你的回答。请检查我的编辑。我忘了补充到目前为止我所想的,以及我想要的答案;您正在寻找一个快速算法,而不仅仅是任何旧代码来给出答案。可能的起点:@Kaz非常感谢您的参考。我会检查它,我也会尝试使用TXR。我正在考虑向Lisp做自我介绍,现在我将尝试Lisp和TXR。谢谢。非常感谢你的回答!真棒的解决方案!谢谢你教我这个虽然起初我认为这是线性的,即使是在最坏的情况下,但现在我想这还不止于此。未使用的前位数函数的时间复杂度是多少?除非它是常数,否则最坏的情况可能是对数(使用一些二进制搜索结构)或线性。我想不出任何方法可以在O(1)
中保留一个未使用的前几位数字表。“你能想出解决办法吗?”鲁本斯说,这是另一个有趣的问题。让我想想。n
能有多大?实际上n
相当小,目前最大值为25。尽管大小很大,我想这可能有助于产生一些特定于语言的解决方案(比如在c/c++中使用位计数),但我还是非常好奇是否有可能在O(1)
中派生出该方法。很高兴看到你也感兴趣!:我能帮忙吗?
[0, 1, 2]
[0, 1, 3]
[0, 2, 1]
[0, 2, 3]
[0, 3, 1]
[0, 3, 2]
[1, 0, 2]
[1, 0, 3]
[1, 2, 0]
[1, 2, 3]
[1, 3, 0]
[1, 3, 2]
[2, 0, 1]
[2, 0, 3]
[2, 1, 0]
[2, 1, 3]
[2, 3, 0]
[2, 3, 1]
[3, 0, 1]
[3, 0, 2]
[3, 1, 0]
[3, 1, 2]
[3, 2, 0]
[3, 2, 1]