在Python中对数字进行分区的方法数

时间:2011-10-18 03:38:47

标签: python list recursion data-partitioning

我已经定义了一个递归函数,它接受一个数字n,并返回list个与该数字相加的数字列表(分区):

def P(n):
    # base case of recursion: zero is the sum of the empty list
    if n == 0:
        yield []
        return

    for p in P(n-1):        
        p.append(1)
        yield p
        p.pop()
        if p and (len(p) < 2 or p[-2] > p[-1]):
            p[-1] += 1
            yield p

我想知道如何让函数返回数字n的分区的 number

例如,P(6)会返回10

3 个答案:

答案 0 :(得分:4)

如果查看Wikipedia上Partiton (number theory)页面的“分区函数公式”部分,您会发现没有简单方法来查找分区号。

相反,你最好的选择可能是:

sum(1 for _ in P(6))

或者,稍微简单但是大量的内存占用

len(list(P(6)))

使用您现有的功能。

另请注意,如果您希望能够保存P返回的值,则应yield p[:]而不是p - 您想要复制,不会反复产生相同的列表(您更改)。你可以看到为什么list(P(6)) - 它会返回一遍又一遍地重复的同一个空列表的列表。

有关分区的更多信息,请参阅Partitioning with Python

答案 1 :(得分:0)

Wolfram Mathworld

P(n,k)表示以正好为k的总和形式写入n 术语,或等效地,划分成部分的数量 最大恰好是k。 (请注意,如果“正好是k”更改为“ k 或更少”和“最大就是k”,更改为“无元素” 大于k”,则获得分区函数q。) 例如,P(5,3)= 2,因为长度为3的5的分区为{3,1,1} 和{2,2,1},元素5为3的5的分区为{3,2} 和{3,1,1}。
...
P(n,k)可以从递归关系中计算出来 P(n,k)= P(n-1,k-1)+ P(n-k,k) (Skiena 1990,第58页; Ruskey),其中k> n,P(n,n)= 1且 P(n,k)= 0 P(n,0)= 0。

因此,如果我们要计算n作为总和的书写方式数,则应计算-

enter image description here

让我们定义P(n,k):

def p(n, k):
    """Gives the number of ways of writing n as a sum of exactly k terms or, equivalently, 
    the number of partitions into parts of which the largest is exactly k.  
    """
    if n < k:
        return 0
    if n == k:
        return 1
    if k == 0:
        return 0

    return p(n-1, k-1) + p(n-k, k)

现在,我们可以计算出n的书写方式总数:

n = 6
partitions_count = 0

for k in range(n + 1):
    partitions_count += p(n, k)

print(partitions_count)

# Output:
# 11

由于p(n, k)是一个递归函数,因此可以通过将每个p(n, k)的值保存在字典中(感谢the fast hash-based search!)来提高速度,并检查是否已计算出该值(在计算之前,请检查该值是否在字典中)

dic = {}
def p(n, k):
    """Gives the number of ways of writing n as a sum of exactly k terms or, equivalently, 
        the number of partitions into parts of which the largest is exactly k.  
    """
    if n < k:
        return 0
    if n == k:
        return 1
    if k == 0:
        return 0

    key = str(n) + ',' + str(k)
    try:
        temp = dic[key]
    except:
        temp = p(n-1, k-1) + p(n-k, k)
        dic[key] = temp
    finally:
        return temp

全功能:

def partitions_count(n):
    """Gives the number of ways of writing the integer n as a sum of positive integers,
    where the order of addends is not considered significant.
    """
    dic = {}
    def p(n, k):
        """Gives the number of ways of writing n as a sum of exactly k terms or, equivalently, 
        the number of partitions into parts of which the largest is exactly k.  
        """
        if n < k:
            return 0
        if n == k:
            return 1
        if k == 0:
            return 0
        
        key = str(n) + ',' + str(k)
        try:
            temp = dic[key]
        except:
            temp = p(n-1, k-1) + p(n-k, k)
            dic[key] = temp
        finally:
            return temp
    
    partitions_count = 0
    for k in range(n + 1):
        partitions_count += p(n, k)
    return partitions_count

有用的链接:

答案 2 :(得分:-2)

以下是Java中用于计算所需结果的示例。

/**
 * Returns the number of ways the number n can be partitioned
 * into sums of positive integers larger than k. 
 * @param k
 * @param n
 * @return
 */
public static long partition(long k, long n){
    long sum = 0;
    if(k > n) return 0;
    if(k == n) return 1;
    sum += partition(k+1, n) + partition(k, n-k);
    return sum;
}