有效地计算一行中给定的一组“块”的排列

时间:2013-01-03 09:12:39

标签: algorithm language-agnostic permutation

我正在开发一个应用程序,其中我有许多块应该放在一行上。即有不同数量的块,每个块都有不同的长度,应该放在线上。块之间至少需要一个空元素。

我希望有效地获得线路上所有可能的排列。

例如,我有一条长度为15的线,并希望放置1个,6个和1个大小的块。

顺序很重要,即在我的例子中,1大小的块总是应该是6大小块的左右。

可能的排列是

X.XXXXXX.X.....
X..XXXXXX.X....
...
.....X.XXXXXX.X

如何以更高级别的语言有效地生成所有可能的排列,例如爪哇?

3 个答案:

答案 0 :(得分:3)

这样做的一种方法是递归接近它:

  1. 如果存储所有块之间只有一个空格所需的最小总长度超过可用空间,则无法放置块。
  2. 否则,如果您没有要放置的区块,那么放置区块的唯一方法是将所有方格都留空。
  3. 否则,有两种选择。首先,您可以将第一个块放在行的第一个位置,然后在行的开头首先留下一个额外的空格后,将剩余的块递归地放置在行内的剩余空间中。其次,您可以将行中的第一个空格留空,然后递归地将同一组块放在行的剩余空间中。尝试两种选择并将结果重新组合在一起应该可以为您提供所需的答案。
  4. 将这种递归逻辑转换为实际的Java应该不会太困难。下面的代码是为了便于阅读而设计的,可以稍微优化一下:

    public List<String> allBlockOrderings(int rowLength, List<Integer> blockSizes) {
        /* Case 1: Not enough space left. */
        if (spaceNeededFor(blockSizes) > rowLength)) return Collections.EMPTY_LIST;
    
        List<String> result = new ArrayList<String>();
    
        /* Case 2: Nothing to place. */
        if (blockSizes.isEmpty()) {
            result.add(stringOf('.', rowLength));
        } else {
            /* Case 3a: place the very first block at the beginning of the row. */
            List<String> placeFirst = allBlockOrderings(rowLength - blockSizes.get(0) - 1,
                                                        blockSizes.subList(1, blockSizes.length()));
            for (String rest: placeFirst) {
                 result.add(stringOf('X', blockSizes.get(0)) + rest);
            }
    
            /* Case 3b: leave the very first spot open. */
            List<String> skipFirst = allBlockOrderings(rowLength - 1, blockSizes);
            for (String rest: skipFirst) {
                 result.add('.' + rest);
            }
        }
        return result;
    }
    

    您需要实现spaceNeededFor方法,该方法返回可能包含给定列块列表的最短行的长度,以及stringOf方法,该方法接收字符和一个数字,然后返回给定字符的那么多副本的字符串。

    希望这有帮助!

答案 1 :(得分:1)

对我而言,以另一种方式思考问题似乎更容易:

我们按固定顺序固定了块,用点分隔。我们可以通过在允许的位置上分配剩余的点来创建所有排列。

该行的固定部分的长度为:

fixed_len = length_of_all_blocks + number_of_blocks - 1

剩余点数

free_dots = length_of_line - fixed_len.

未结头寸的数量是

pos_count = number_of_blocks + 1

现在我们必须找到如何将free_dots放入pos_count的所有排列。

答案 2 :(得分:0)

很难确定什么是“有效实现”,因为输出可能非常大,因此即使快速实现也不够快。

我会使用动态编程和递归技术来完成这项任务。递归的fuoction应该有两个参数 - 未使用的数字列表和行的剩余长度。在里面它将是一个简单的循环。您应该存储您已经知道的结果。我相信你可以自己处理细节。编辑:我们的朋友已经为你完成了这件事: - )。

顺便说一下,这样的任务的目标是什么?它让我重新关注网格中的图片,其中每行和每列都有这样的数字,你需要解码图片。有更好的方法来解决这个问题。