2017-03-15 6 views
3

長さが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が増加し、ユニークな要素の数が減少すると、その差は大きくなります。だから、:

は中間すべて順列を維持せずに、非個別のオブジェクトを含む配列のすべてのユニークな順列をリストアップする(うまくいけば内蔵)方法はありますか?以下

答えて

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 

さらにJan Simon's functionsの一つとnchoosekを置換することによって改善することができます。

+0

ニース!それは確かに他の方法よりも速いです。私はそのスレッドを見ましたが、私はこの解決策を見落とさなければならないでしょう。残念ながら私はnchoosek置換関数をコンパイルできませんが、これはAskUbuntu上でより良いスレッドを作成します:) – UJIN

関連する問題