【问题标题】:How to compute all unique permutations and keep the same positive adjacent elements always adjacent?如何计算所有唯一排列并保持相同的正相邻元素始终相邻?
【发布时间】:2017-10-27 05:19:54
【问题描述】:

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

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

在 Matlab 下,以V=[2, 3, 3, 0, 0] 为例,我得到的所有唯一排列如下:

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

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

【问题讨论】:

  • 你希望所有的正数都在一起还是只有相同的正数在一起?
  • 我希望所有相同且相邻的正数都在一起(保持相邻)。
  • 将相邻元素的每个“运行”视为一个元素,然后使用任何标准排列算法。

标签: algorithm combinations


【解决方案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)}

【讨论】:

    【解决方案2】:

    一个简单的算法是:

    1.遍历初始表并制作另一个具有两行的表,如:

    input: V = [2, 3, 3, 0, 0];
    
    new array: V2 = |2,3,0|
                    |1,2,2|
    

    如您所见,V2 来自 V,将元素保留一次,并在第二行计算我们看到它们的次数。

    1. 现在生成列的所有排列

    对于每个结果,例如:

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

    你记录了元素出现的次数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多