给定整数作为输入,打印所有唯一的整数分区

时间:2013-07-18 09:50:33

标签: algorithm recursion numbers decomposition partition-problem

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

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

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

4 个答案:

答案 0 :(得分:17)

我会这样接近:

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

printPartitions(int target, int maxValue, string suffix)

符合规范:

  

打印目标的所有整数分区,后跟后缀,以便分区中的每个值最多为maxValue

请注意,始终至少有一个解决方案(前提是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 

答案 1 :(得分:3)

这是从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, "");
}

答案 2 :(得分:1)

枚举数字 n 的整数分区的过程是递归的。有一个0的分区,空集()。单个分区为1,即集合(1)。有两个分区2,集合(1 1)和(2)。有三个分区3,集合(1 1 1),(1 2)和(3)。有4个分区,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))

答案 3 :(得分:0)

这是一个算法。让我知道你的想法。在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)