如何计算所有独特的排列并保持相同的正相邻元素始终相邻?

时间:2017-10-26 20:42:48

标签: algorithm combinations

我有V非负整数的列表或向量n。有一些正整数相等且相邻,比如V=[2, 3, 3, 0, 0]。 (我不关心零整数。)

我想找到V的所有唯一排列,以便所有相同且正整数保持相邻。如何为此编写算法? (对于实现,您可以选择Python或Matlab或任何其他语言。)

在Matlab和V=[2, 3, 3, 0, 0]的例子中,我得到了所有独特的permations如下:

V = [2, 3, 3, 0, 0];
unique(perms([2, 3, 3, 0, 0]), 'rows')

我得到了:

 0     0     2     3     3
 0     0     3     2     3
 0     0     3     3     2
 0     2     0     3     3
 0     2     3     0     3
 0     2     3     3     0
 0     3     0     2     3
 0     3     0     3     2
 0     3     2     0     3
 0     3     2     3     0
 0     3     3     0     2
 0     3     3     2     0
 2     0     0     3     3
 2     0     3     0     3
 2     0     3     3     0
 2     3     0     0     3
 2     3     0     3     0
 2     3     3     0     0
 3     0     0     2     3
 3     0     0     3     2
 3     0     2     0     3
 3     0     2     3     0
 3     0     3     0     2
 3     0     3     2     0
 3     2     0     0     3
 3     2     0     3     0
 3     2     3     0     0
 3     3     0     0     2
 3     3     0     2     0
 3     3     2     0     0

如你所知,我得到30这样的排列。在这些30中,有18不尊重邻接约束。例如,[3, 2, 3, 0, 0]不能出现在最终结果中,因为3不再与3相邻。最后,所有独特的排列都可以通过以下方式给出:

 0     0     2     3     3
 0     0     3     3     2
 0     2     0     3     3
 0     2     3     3     0
 0     3     3     0     2
 0     3     3     2     0
 2     0     0     3     3
 2     0     3     3     0
 2     3     3     0     0
 3     3     0     0     2
 3     3     0     2     0
 3     3     2     0     0

我想到的第一个想法(也是最简单的想法)是生成所有独特的排列,然后为每个排列验证约束。但是还有其他有效的算法吗?

2 个答案:

答案 0 :(得分:1)

一个简单的算法是:

1.遍历初始表并创建另一个包含两行的表:

input: V = [2, 3, 3, 0, 0];

new array: V2 = |2,3,0|
                |1,2,2|

正如你所看到的,V2来自V,保留一次元素,第二行计算我们看到它们的次数。

  1. 现在生成列的所有排列
  2. 对于每一个结果,例如:

    V2 = |3,2,0|
         |2,1,2|    
    

    你已经保留了元素出现的次数。

答案 1 :(得分:1)

  • 我们可以先压缩给定的数组,这样每个正数只有一个条目,同时保持每个数字出现次数的计数(零应保留原样)。

  • 生成压缩数组的排列。

  • 解压缩每个排列并仅保留唯一排列。

要压缩

def compress(arr):
    counts = {}
    compressed = []
    curr_ele = arr[0]
    count_ele = 0
    for ele in arr:
        if ele != curr_ele or ele == 0:
            counts[curr_ele] = count_ele
            compressed.append(curr_ele)
            count_ele = 1
            curr_ele = ele
        else:
            count_ele += 1
    counts[curr_ele] = count_ele
    compressed.append(curr_ele)
    return compressed, counts

解压缩

def uncompress(arr, counts):
    res = []
    for ele in arr:
        if ele == 0:
            res.append(0)
            continue
        num_reps = counts[ele]
        for _ in range(num_reps):
            res.append(ele)
    return res

将它们放在一起:压缩,置换,解压缩并保留唯一

import itertools
ip = [2, 3, 3, 0, 0]
ip_compressed, counts = compress(ip)
set([tuple(uncompress(perm, counts)) for perm in itertools.permutations(ip_compressed)])

结果:

{(0, 0, 2, 3, 3),
 (0, 0, 3, 3, 2),
 (0, 2, 0, 3, 3),
 (0, 2, 3, 3, 0),
 (0, 3, 3, 0, 2),
 (0, 3, 3, 2, 0),
 (2, 0, 0, 3, 3),
 (2, 0, 3, 3, 0),
 (2, 3, 3, 0, 0),
 (3, 3, 0, 0, 2),
 (3, 3, 0, 2, 0),
 (3, 3, 2, 0, 0)}