假设我有一个重新排序的矩阵A
,可以在MATLAB中使用A = nchoosek(1:100, 6)
得到。因此,A
表示从1到100中选择6位数的所有组合。
A
已重新排序,A
的昏暗非常大(1e9 * 6),因此A
是这样的:
1 2 3 4 5 6
1 2 3 4 5 7
1 2 3 4 5 8
. . . . . .
. . . . . .
94 96 97 98 99 100
95 96 97 98 99 100
然后,我有另一个重新排序的向量B
,它是A
的成员。例如B=[5 10 11 40 51 67];
那么,如何使用最快的方式找到B
的索引,这意味着利用订购信息?
答案 0 :(得分:3)
您应该注意如何生成A
行。我怀疑文档中没有指定,所以你可能不应该过多地依赖它。我的意思是,这是技术上没有文档记录的行为,它可以随任何版本而改变。
但请注意,每个元素从结束索引开始循环,并且每个组合都被排序。这意味着您需要从头开始,在
中B = [5 10 11 40 51 67];
第一个索引是5,这意味着枚举了以4
开头的所有元素。有多少人?
nchoosek(100-1,6-1)+nchoosek(100-2,6-1)+nchoosek(100-3,6-1)+nchoosek(100-4,6-1)
% [1 . . . . .] [2 . . . . .] [3 . . . . .] [4 . . . . .]
% ^ 2:100 ^ 3:100 ^ 4:100 ^ 5:100
因为如果第一个元素是1,我们有99个数字可以选择5,如果第一个数字是2则从98中选择5,等等。
接下来是元素[5 6 7 8 9 10]
到[5 9 97 98 99 100]
。同样,如果第二个元素是固定的,这些是完整的组合:
nchoosek(100-6,6-2)+nchoosek(100-7,6-2)+nchoosek(100-8,6-2)+nchoosek(100-9,6-2)
% [5 6 . . . .] [5 7 . . . .] [5 8 . . . .] [5 9 . . . .]
% ^ 7:100 ^ 8:100 ^ 9:100 ^ 10:100
依此类推,直到你构建了[5 10 11 40 50 .]
的所有内容,其中包含nchoosek(100-50,6-5)
的最后一个词。然后剩下的就是计算从[5 10 11 40 51 52]
到[5 10 11 40 51 67]
的元素,即67-52+1
。
因此,如果您的索引向量B
有n个元素,每个都为b_k
调用k=1:n
,请将其形式化:
sum_{k=1:n} sum_{b=b_{k-1}+1:b_{k}-1} nchoosek(100-b,n-k)
如果我们将第一个索引的b_0
定义为零,则会有效,请注意nchoosek(m,0)==1
。
所以这是一个应该有用的简单功能。它在同类中并不是最优的,但它确实胜过检查1e9向量相互之间的对比:
function ind = find_chooseind(N,B)
% N is the N in 1:N in nchoosek(1:N,K)
% length(B) == K
% define auxiliary B with a zero prepended to avoid out-of-bounds errors
Blen = length(B);
B = [0; B(:)];
ind = 0;
for k=2:Blen+1 % shifted for that first zero
for b=B(k-1)+1:B(k)-1
ind = ind + nchoosek(N-b,Blen-(k-1)); % compensate for k shift
end
end
% testing reveals an off-by-one error, not to worry
ind = ind+1;
我用一个较小的例子测试了上面的代码:
>> N = 20; K = 4;
>> A20_4 = nchoosek(1:N,K);
>> t = A20_4(randi(nchoosek(N,K)),:);
>> ind = find_chooseind(N,t);
>> A20_4(ind,:)
ans =
7 8 9 14
>> t
t =
7 8 9 14