递归整数分区算法

时间:2012-09-28 13:10:44

标签: scala partitioning

我试图计算我可以分割整数的方法。到目前为止,我想出了以下功能:

def partition(num: Int): Int = {
    if(num == 1) return 1
    if(num <= 0) return 0
    return partition(num-1) + partition(num-(num-1))
}
partition(6) //6 instead of 7  

例如:5 -> 4 + 1, 3 + 2, 2 + 2 + 1, 2 + 1 + 1 + 1, 1 + 1 + 1 + 1 + 1

如果num为1,则返回1,因为我认为partition(1)就是结束。

也许你可以发现其中的逻辑错误?

5 个答案:

答案 0 :(得分:4)

我认为这有效:

def partition(n: Int): Int = {
  def inner(n: Int, max: Int): Int =
    if (n == 0) 1
    else if (n < 0) 0
    else ((1 to max) map (x => inner(n - x, x))).sum

  if (n == 0) 0
  else inner(n, n-1)
}

整数n可以划分为(n-1) + (any way of partitioning 1)(n-2) + (any way of partitioning 2),...,1 + (any way of partitioning (n-1))。但是,为partition(m)天真地计算m = 1 to n-1并对结果求和将计算一些分区n两次的方法,例如1 + (n-1)(n-1) + 1

我们可以通过将分区视为一个正整数序列i{j} < n并求n来解决此问题,并且只考虑 ordered 的序列。 inner方法具有max参数,可确保仅考虑i{j} >= i{j+1}的序列。所以它会考虑例如2 + 1,但不是1 + 2

n == 0在上面的代码中是一个烦人的边缘情况,因为你实际上不想计算空序列。

答案 1 :(得分:2)

def partition(n: Int): Int = {
    def partDecr(n: Int, decr: Int): Int = {
        if (n == 0) 1
        else if (n < 0 || decr == 0) 0
        else partDecr(n - decr, decr) + partDecr(n, decr - 1)
    }
    partDecr(n, n)
}
  • 内部函数采用额外的参数指定下一个可能的减量。
  • 首先检查我们是否处于有效终点(找到1个解决方案)。
  • 然后检查我们是否可以继续(积极休息分区,然后积极减少尝试下一步)。
  • 然后它以两种方式递归:
    • 第一个“获取”当前的减量并减少n,
    • 第二个“跳过”当前的减量并将尝试使用下一个较低的减量。

请注意,这不是尾递归,可以使用相当多的堆栈空间,但速度太慢并不重要。

答案 2 :(得分:1)

我认为没有“那么简单”的算法来计算你想要的东西。 OP中提出的算法不会出于几个原因(我不会讨论)。

但是我引导你到Wikipedia entry on 'Partition',它还包括一个递归公式。

请注意,这个确切的公式在计算上比OP中提出的算法更复杂,也更复杂。

答案 3 :(得分:1)

我认为它需要另一个参数(可以构成分区的整数,称之为madeOf)。这样你可以将问题分成2个严格较小的子集。 partition(num, madeOf=(n, n-1, ..., 1))的计数是

的总和
  • partition(num, madeOf=(n-1, ..., 1))(所有不包含n的分区)
  • partition(num-n, madeOf(n, n-1, ..., 1))(所有至少有一个n的分区)

然后,您可以使其更加优化,因为madeOf只能由一个int构建:

def part(num: Int, madeOf: Int): Int =
  if (num == 0) 1 // we found a partition!
  else if (num < 0) 0 // no partition...
  else if (madeOf == 0) 0 // no more ways to make partition
  else part(num, madeOf - 1) +  // all the partitions that don't contain n
    part(num - madeOf, madeOf)  // all the partition that contain n

part(5, 4) // 6

答案 4 :(得分:0)

您可以使用以下内部函数 - 您只需要创建一个包含数字&lt;的列表。要分区的号码。例如,您想要分区4,那么intNumber应该是(1,2,3,4)

  def partition(number: Int, intNumbers: List[Int]): Int = {    
if (number <= 0 || intNumbers.isEmpty) 
  0
else if ((number-intNumbers.head)==0) 
  1+partition(number-intNumbers.head,intNumbers)+partition(number,intNumbers.tail)
else 
  partition(number-intNumbers.head,intNumbers)+partition(number,intNumbers.tail)