【问题标题】:Print all unique integer partitions given an integer as input打印给定整数作为输入的所有唯一整数分区
【发布时间】:2013-07-17 04:52:55
【问题描述】:

我正在解决一个编程练习,遇到了一个我无法令人满意地找到解决方案的问题。 问题如下:

Print all unique integer partitions given an integer as input.
Integer partition is a way of writing n as a sum of positive integers.

例如: 输入=4 那么输出应该是 输出=

  1 1 1 1
  1 1 2
  2 2
  1 3
  4

我应该如何考虑解决这个问题? 我想知道使用递归。谁能为我提供这个问题的算法? 或对解决方案的提示。 欢迎对此类问题进行任何解释。 (我是编程世界的初学者) 谢谢!!

【问题讨论】:

    标签: algorithm recursion numbers decomposition partition-problem


    【解决方案1】:

    我会这样处理:

    首先,概括问题。你可以定义一个函数

    printPartitions(int target, int maxValue, string suffix)
    

    与规范:

    打印target的所有整数分区,后跟后缀,使得分区中的每个值最多为maxValue

    请注意,始终存在至少 1 个解(假设 target 和 maxValue 均为正数),即全为 1。


    您可以递归地使用此方法。因此,让我们首先考虑基本情况:

    printPartitions(0, maxValue, suffix)
    

    应该简单地打印suffix


    如果target 不是0,您必须选择:使用maxValue 或不使用(如果maxValue > target 只有一个选项:不要使用它)。如果你不使用它,你应该将maxValue降低1

    即:

    if (maxValue <= target)
        printPartitions(target-maxValue, maxValue, maxValue + suffix);
    if (maxValue > 1)
        printPartitions(target, maxValue-1, suffix);
    

    将这一切结合起来会产生一个相对简单的方法(这里用 Java 编码,我对语句进行了一点重新排序以获得与您描述的完全相同的顺序):

    void printPartitions(int target, int maxValue, String suffix) {
        if (target == 0)
            System.out.println(suffix);
        else {
            if (maxValue > 1)
                printPartitions(target, maxValue-1, suffix);
            if (maxValue <= target)
                printPartitions(target-maxValue, maxValue, maxValue + " " + suffix);
        }
    }
    

    你可以简单地称之为

    printPartitions(4, 4, "");
    

    哪个输出

    1 1 1 1 
    1 1 2 
    2 2 
    1 3 
    4 
    

    您也可以选择先创建所有解决方案的列表,然后再打印,如下所示:

    function createPartitions(target, maxValue, suffix, partitions) {
      if (target == 0) {
        partitions.push(suffix);
      } else {
        if (maxValue > 1)
          createPartitions(target, maxValue-1, suffix, partitions);
        if (maxValue <= target)
          createPartitions(target-maxValue, maxValue, [maxValue, ...suffix], partitions);
      }
    }
    
    const partitions = [];
    createPartitions(4, 4, [], partitions);
    console.log(partitions);

    【讨论】:

    • 如何解决这个方法来填充List&lt;int[]&gt; partitions = new ArrayList&lt;&gt;();
    • @Eftekhari 1) 将suffix 的类型从String 更改为int[],2) 将maxValue + " " suffix 更改为在maxValue 前面添加suffix 的内容,3)添加函数参数List&lt;int[]&gt; partitions并在初始调用时传递空列表,4)将System.out.println(suffix)更改为partitions.add(suffix)
    • 它没有用。数组大于数字。请您尝试一下以确保它有效吗?
    • @Eftekhari 我现在在答案中添加了一个可运行的 javascript sn-p。你可以在 Java 中做类似的事情。
    【解决方案2】:

    这大致源自Heuster's approach

    首先,请注意输出的最后一个数字是1,2,2,3,4。如果最后一个数字是2,则倒数第二个数字是1,2。这告诉我,使用带有 for 循环的递归函数从后面生成字符串可能是个好主意。

    代码本身非常简单:

    • 从 1 循环到 target,将变量添加到后缀,从 target 中减去它并递归。
    • 还要注意,每个生成的字符串都经过排序(这隐含地避免了输出重复)。我们只需传入最后生成的数字并循环不超过该数字即可对其进行排序。

    代码:

    private void printPartitions(int target, int max, String suffix)
    {
        if (target == 0)
           System.out.println(suffix);
        else
        {
           for (int i = 1; i <= max && i <= target; i++)
              printPartitions(target - i, i, i + " " + suffix);
        }
    }
    

    调用函数:

    public void printPartitions(int target)
    {
       printPartitions(target, target, "");
    }
    

    【讨论】:

    • 是的,这样你就可以摆脱深度递归并且代码更短:)我发现另一个更容易解释:)
    • 上述方案的时间复杂度是多少?
    【解决方案3】:

    枚举数字n的整数分区的过程是递归的。有一个0的单分区,空集()。有一个单一的分区 1,集合 (1)。有 2 的两个分区,集合 (1 1) 和 (2)。有 3 的三个分区,集合 (1 1 1)、(1 2) 和 (3)。有 4 个的五个分区,即集合 (1 1 1 1)、(1 1 2)、(1 3)、(2 2) 和 (4)。有 5 个的七个分区,即集合 (1 1 1 1 1)、(1 1 1 2)、(1 2 2)、(1 1 3)、(1 4)、(2 3) 和 (5)。等等。在每种情况下,通过将小于或等于 n 的每个整数 x 添加到由 的分区形成的所有集合中来确定下一个更大的分区集合n - x,消除任何重复。

    我在my blog 提供多种语言的代码。例如,这是我在 Scheme 中的解决方案:

    (define (set-cons x xs)
      (if (member x xs) xs
        (cons x xs)))
    
    (define (parts n)
      (if (zero? n) (list (list))
        (let ((xs (list)))
          (do ((x 1 (+ x 1))) ((= x n) (cons (list n) xs))
            (do ((yss (parts (- n x)) (cdr yss))) ((null? yss))
              (set! xs (set-cons (sort < (cons x (car yss))) xs)))))))
    
    > (parts 0)
    (())
    > (parts 1)
    ((1))
    > (parts 2)
    ((2) (1 1))
    > (parts 3)
    ((3) (1 1 1) (1 2))
    > (parts 4)
    ((4) (2 2) (1 1 2) (1 1 1 1) (1 3))
    > (parts 5)
    ((5) (2 3) (1 1 3) (1 1 1 1 1) (1 1 1 2) (1 2 2) (1 4))
    > (parts 6)
    ((6) (3 3) (2 2 2) (2 4) (1 1 4) (1 1 2 2) (1 1 1 1 2)
      ((1 1 1 1 1 1) (1 1 1 3) (1 2 3) (1 5))
    

    【讨论】:

      【解决方案4】:

      这是一个算法。让我知道你的想法。在python3上测试

      def partition(A):
          table = [[[1]]] + [None]*(A-1)
          for i in range(1,A):
              table[i] = [[i+1]]
              for k in range(i):
                  table[i].extend([[i-k]+l for l in table[k] if i-k >= l[0]])
          return table[-1]
      
      def print_partition(A):
          for i in reversed(partition(A)): print(*i)
      

      【讨论】:

      • 能否修改为仅包含具有不同部分的分区?
      • 不同部分是什么意思?例子?
      • 4 的分区是 [4]、[3,1]、[2,2] 和 [1,1,1,1]。但是具有不同部分的分区是 [4] 和 [3,1],因为其他分区包含重复项。请参阅有关奇数部分和不同部分的部分 -> en.m.wikipedia.org/wiki/Partition_(number_theory)
      • 是的。只需将i-k &gt;= l[0] 更改为i-k &gt; l[0] :)
      • 只是给你一个想法,我的代码使用动态编程。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-14
      • 2021-07-25
      • 1970-01-01
      • 2013-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多