题目:
My little sister came back home from school with the following task: given a squared sheet of paper she has to cut it in pieces which, when assembled, give squares the sides of which form an increasing sequence of numbers. At the beginning it was lot of fun but little by little we were tired of seeing the pile of torn paper. So we decided to write a program that could help us and protects trees.
Task
Given a positive integral number n, return a strictly increasing sequence (list/array/string depending on the language) of numbers, so that the sum of the squares is equal to n².
If there are multiple solutions (and there will be), return as far as possible the result with the largest possible values:
Examples
decompose(11) must return [1,2,4,10]. Note that there are actually two ways to decompose 11², 11² = 121 = 1 + 4 + 16 + 100 = 1² + 2² + 4² + 10² but don’t return [2,6,9], since 9 is smaller than 10.
For decompose(50) don’t return [1, 1, 4, 9, 49] but [1, 3, 5, 8, 49] since [1, 1, 4, 9, 49] doesn’t form a strictly increasing sequence.
Note
Neither [n] nor [1,1,1,…,1] are valid solutions. If no valid solution exists, return nil, null, Nothing, None (depending on the language) or “[]” © ,{} (C++), [] (Swift, Go).
The function “decompose” will take a positive integer n and return the decomposition of N = n² as:
[x1 … xk] or
“x1 … xk” or
Just [x1 … xk] or
Some [x1 … xk] or
{x1 … xk} or
“[x1,x2, … ,xk]”
depending on the language (see “Sample tests”)
Note for Bash
decompose 50 returns "1,3,5,8,49"
decompose 4 returns "Nothing"
Hint
Very often xk will be n-1.
我的思路:
题目是要我们把一个数字的平方分解为几个数字的平方之和。其中有两个要求,一是要返回一个严格上升的数列,即不能有两个相等的数字;另一个是分出的数字尽可能大,如第一个例子所示,11的平方应该分成 [1,2,4,10],而不是[2,6,9],因为9 < 10。
所以我打算先尽可能大地分配,如果无法满足条件,再从最小一位开始调整,试试它如果再小一点能不能分配出满足条件的结果,如果不行,则调整倒数第二位。
result里放的是尽可能大地分配的结果。remain用来放分配后的余数。如果余数为0,则从小到大排列并return,如果余数大于0,则从最小一位开始调整,最小一位没法调整时,把最小一位去掉,放入remain中,再调整前一位。
我的解答:
def decompose(n):
remain = 0
result = [n]
while result:
current = result.pop()
remain += current ** 2
for i in range(current - 1, 0, -1):
if remain - (i ** 2) >= 0:
remain -= i ** 2
result.append(i)
if remain == 0:
result.sort()
return result
return None
Most Clever:
做完题目看一下题后投票clever最多的答案:
def decompose(n):
def _recurse(s, i):
if s < 0:
return None
if s == 0:
return []
for j in xrange(i-1, 0, -1):
sub = _recurse(s - j**2, j)
if sub != None:
return sub + [j]
return _recurse(n**2, n)
他构建了一个递归函数,地毯式搜索。每次调用 _recurse() 的时候print一下s和 i,更直观地看一下思路。
可以看出,如果s为负数,即上一次中的 (s - j**2) 为负,则return None,退出递归,j减一后再次进入递归。
另外,这段代码要在python2运行。
总结:
两种方法思路基本一致,Most Clever运算的顺序跟我的算法基本一样,都是先尽可能大地分配,然后再从小到大开始调整。