假设我有一个长度N
且M
个不同对象(M < N
)的数组,以便其中一些对象重复N_i ... N_M
次。我想找到这些数组元素的所有可能的唯一处置(比如,排列),而不事先计算整个排列列表(包括时间和内存约束)。
当然,天真的解决方案是使用perms
生成所有可能的排列,然后选择唯一的排列:
A = [1, 1, 2];
all_perms = perms(A)
% all_perms =
% 2 1 1
% 2 1 1
% 1 2 1
% 1 1 2
% 1 2 1
% 1 1 2
unique_perms = unique(all_perms, 'rows')
% unique_perms =
% 1 1 2
% 1 2 1
% 2 1 1
但这会生成所有 N!
排列,而不仅仅是N! / (N_1! * N_2! * ... * N_M!)
。对于N = 3
,这不会对内存消耗和时序产生太大影响,但随着N
的增加和唯一元素的数量减少,差异可能会很大。所以:
是否有(希望是内置的)方法列出包含非不同对象的数组的所有唯一排列,而不是中间保留所有排列?
答案 0 :(得分:3)
以下是Bruno Luong针对此问题在2014年建议的代码:
function p = uperm(a)
[u, ~, J] = unique(a);
p = u(up(J, length(a)));
end % uperm
function p = up(J, n)
ktab = histc(J,1:max(J));
l = n;
p = zeros(1, n);
s = 1;
for i=1:length(ktab)
k = ktab(i);
c = nchoosek(1:l, k);
m = size(c,1);
[t, ~] = find(~p.');
t = reshape(t, [], s);
c = t(c,:)';
s = s*m;
r = repmat((1:s)',[1 k]);
q = accumarray([r(:) c(:)], i, [s n]);
p = repmat(p, [m 1]) + q;
l = l - k;
end
end
将nchoosek
替换为Jan Simon's functions之一,可以进一步改善上述情况。