标签:
问题出于codewars,简言之:寻找和为一个整数的的不同整数组合。https://en.wikipedia.org/wiki/Partition_(number_theory)
例如:和为6的整数组合有如下11种,
6
5 + 1
4 + 2
4 + 1 + 1
3 + 3
3 + 2 + 1
3 + 1 + 1 + 1
2 + 2 + 2
2 + 2 + 1 + 1
2 + 1 + 1 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1 + 1
解法一:
为了避免重复,我们可以选择逐渐递减第一个加数,直到不小于n的一半(保持分解的数字),然后对第一个加数应用这个策略,还是以6为例:
6
5 + 1
4 + 2
3 + 3
然后对第一个加数5应用这个策略,
4 + 1
3 + 2
接着对分解4和3应用这一策略,得到如下:
6
5 + 1
4 + 1 + 1
3 + 1 + 1 + 1
2 + 1 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1 + 1
2 + 2 + 1 + 1
3 + 2 + 1
4 + 2
2 + 2 + 2
3 + 3
因为我们已经有了3+2+1,对于4而言就不在分解成3+1+2,此处的限制条件分解4不能产生比2(4后面的2)小的数字,所以只能是2+2,同理,3就不再分解了,因为分解不出比3(后面那个)还大的数了。
1 def exp_sum(n): 2 if n < 0: 3 return 0 4 if n == 0: 5 return 1 6 return help(n, 1) 7 8 def help(n, mini): 9 tmp = 1 10 if n <= 1: 11 return 1 12 for i in range(1, n/2+1):##保证n-i不小于i 13 if i >= mini: ##保证分解得到的数不小于后面的较小的数 14 tmp = tmp + help(n-i, i) 15 return tmp 16 print exp_sum(6)
当然了,这个递归的速度是很慢的,T(n) = T(n-1) + T(n-2) +...+ T(ceil(n/2)),时间复杂度是指数级别的。
解法二:
可以开辟一个大小为n的list存储已经计算的结果:
1 def exp_sum(n): 2 if n < 0: 3 return 0 4 if n == 0 or n == 1: 5 return 1 6 solution = [1] + [0]*n 7 8 for i in range(1, n): 9 for j in range(i, n+1): 10 solution[j] += solution[j-i] 11 return solution[n]+1
解法三:
根据维基百科上的generation function:p(k) = p(k − 1) + p(k − 2) − p(k − 5) − p(k − 7) + p(k − 12) + p(k − 15) − p(k − 22) − ... + (-1)^(k+1)*p(k − (3k^2 - k)/2) + (-1)^(k+1)*p(k − (3k^2 + k)/2)
1 def exp_sum(n): 2 solutions = [1]*(n + 1) 3 4 for i in xrange(1, n + 1): 5 j, k, s = 1, 1, 0 6 while j > 0: 7 j = i - (3 * k * k + k) / 2 8 if j >= 0: 9 s += (-1) ** (k+1) * solutions[j] 10 j = i - (3 * k * k - k) / 2 11 if j >= 0: 12 s += (-1) ** (k+1) * solutions[j] 13 k += 1 14 solutions[i] = s 15 16 return solutions[n]
参考链接:
https://en.wikipedia.org/wiki/Partition_(number_theory)
http://stackoverflow.com/questions/438540/projecteuler-sum-combinations
2015-07-15 17:03:25
PARTITION(number theory) ALSO Explosive number in codewars
标签:
原文地址:http://www.cnblogs.com/FARAMIR/p/4648905.html