找到数字平方和与给定数字相加的最小整数
Posted
技术标签:
【中文标题】找到数字平方和与给定数字相加的最小整数【英文标题】:Find the smallest integer whose sum of squares of digits add to the given number 【发布时间】:2016-11-12 15:00:02 【问题描述】:示例:
输入:|输出:
5 –> 12 (1^2 + 2^2 = 5)
500 -> 18888999 (1^2 + 8^2 + 8^2 + 8^2 + 9^2 + 9^2 + 9^2 = 500)
我已经编写了一个非常简单的蛮力解决方案,但它存在很大的性能问题:
#include <iostream>
using namespace std;
int main()
int n;
bool found = true;
unsigned long int sum = 0;
cin >> n;
int i = 0;
while (found)
++i;
if (n == 0) //The code below doesn't work if n = 0, so we assign value to sum right away (in case n = 0)
sum = 0;
break;
int j = i;
while (j != 0) //After each iteration, j's last digit gets stripped away (j /= 10), so we want to stop right when j becomes 0
sum += (j % 10) * (j % 10); //After each iteration, sum gets increased by *(last digit of j)^2*. (j % 10) gets the last digit of j
j /= 10;
if (sum == n) //If we meet our problem's requirements, so that sum of j's each digit squared is equal to the given number n, loop breaks and we get our result
break;
sum = 0; //Otherwise, sum gets nullified and the loops starts over
cout << i;
return 0;
我正在寻找问题的快速解决方案。
【问题讨论】:
你的问题不是很好。例如,您可以说any number -> 1111111...1111
。这将是一个微不足道但正确但有效的解决方案。我认为你必须回到制定阶段。
问题说明“找到最小的整数,其数字的平方和与给定的数字相加”
我的错,你是对的!这个问题比看起来更有趣,可能应该更好地评估。我建议在问题正文中完整地陈述问题,而不是依赖问题标题。
我的基本原理是将n
除以81
,得到9
的数量。然后取还押,除以64
,也就是8
的个数,以此类推……
请注意,结果中数字的所有排列都具有相同的属性。因此,一种可能的解决方案可能是找到最小的完美平方集合
【参考方案1】:
使用动态编程。如果我们知道最优解的第一个数字,那么其余的将是总和剩余部分的最优解。因此,我们可以猜测第一个数字,并针对较小的目标使用缓存计算来获得最佳值。
def digitsum(n):
best = [0]
for i in range(1, n+1):
best.append(min(int(str(d) + str(best[i - d**2]).strip('0'))
for d in range(1, 10)
if i >= d**2))
return best[n]
【讨论】:
我刚开始竞争编程,所以动态编程对我来说是一个有待发现的话题。您能否在代码中添加一些解释,使其不那么深奥且更易于理解?非常感谢 @RafaelSofi-Zadeh 那里有很多教程材料。也许你应该从那开始。 @Rafael Sofi-Zadeh 我会建议你 this book 我相信它会很快让你了解动态规划。【参考方案2】:让我们试着解释一下大卫的解决方案。我相信他的假设是给定一个最优解abcd...
,n - a^2
的最优解是bcd...
,因此如果我们计算从1
到n
的所有解,我们可以依赖以前的解对于小于n
的数字,我们会尝试不同的减法。
那么我们该如何解读大卫的代码呢?
(1) 将数字 1 到 n
的解按顺序放入表格 best
:
for i in range(1, n+1):
best.append(...
(2) 当前查询i
的解是在1
和9
之间的不同数字d
的选择数组中的最小值,如果从i
中减去d^2
是可行的。
转换为整数的最小值...
min(int(
...字符串,d
,与先前记录在表中的n - d^2
的解的字符串连接起来(去除连接为零的解):
str(d) + str(best[i - d**2]).strip('0')
让我们修改 David 的代码的最后一行,看看表格是如何工作的示例:
def digitsum(n):
best = [0]
for i in range(1, n+1):
best.append(min(int(str(d) + str(best[i - d**2]).strip('0'))
for d in range(1, 10)
if i >= d**2))
return best # original line was 'return best[n]'
我们打电话给digitsum(10)
:
=> [0, 1, 11, 111, 2, 12, 112, 1112, 22, 3, 13]
当我们到达i = 5
时,我们对d
的选择是1
和2
,所以选择数组是:
min([ int(str(1) + str(best[5 - 1])), int(str(2) + str(best[5 - 4])) ])
=> min([ int( '1' + '2' ), int( '2' + '1' ) ])
等等等等。
【讨论】:
【参考方案3】:所以这实际上是一个众所周知的变相问题。 The minimum coin change problem 给你一笔钱,并要求你用最少数量的硬币支付。在这里,我们有 81、64、49、36、...、1 美分,而不是 1 美分、5 美分、1 美分和 25 美分。
显然这是一个鼓励动态编程的典型例子。在动态编程中,与期望从上到下的递归方法不同,您现在期望从下到上并“记忆”稍后需要的结果。因此...更快..!
好吧,这是我在 JS 中的方法。它可能与 David 的方法非常相似。
function getMinNumber(n)
var sls = Array(n).fill(),
sct = [], max;
sls.map((_,i,a) => max = Math.min(9,~~Math.sqrt(i+1)),
sct = [];
while (max) sct.push(a[i-max*max] ? a[i-max*max].concat(max--)
: [max--]);
a[i] = sct.reduce((p,c) => p.length < c.length ? p : c);
);
return sls[sls.length-1].reverse().join("");
console.log(getMinNumber(500));
我们正在做的是从下到上生成一个名为sls
的查找数组。这就是记忆发生的地方。然后从1
到n
,我们在几个选择中映射出最好的结果。例如,如果我们要查找 10
的分区,我们将从 10 的平方根的整数部分开始,即 3,并将其保存在 max
变量中。所以 3 是其中一个数字,另一个应该是 10-3*3 = 1。然后我们查找先前解决的 1
,实际上是 [1]
sls[0]
和 concat 3 到 sls[0]
。结果是[3,1]
。一旦我们用 3 完成,然后一个接一个地从一个较小的工作开始,直到它是 1。所以在 3 之后我们检查 2(结果是 [2,2,1,1]
)然后检查 1(结果是 [1,1,1,1,1,1,1,1,1,1]
)和比较 3、2 和 1 的结果的长度最短,即 [3,1]
并将其存储在 sls[9]
(又名 a[i]
),这是我们查找数组中 10 的位置。
【讨论】:
【参考方案4】:(编辑)这个答案不正确。贪婪的方法不适用于这个问题——抱歉。
我将以与语言无关的方式给出我的解决方案,即算法。 我还没有测试过,但我相信这应该可以解决问题,并且复杂度与输出中的位数成正比:
digitSquared(n)
% compute the occurrences of each digit
numberOfDigits = [0 0 0 0 0 0 0 0 0]
for m from 9 to 1
numberOfDigits[m] = n / m*m;
n = n % m*m;
if (n==0)
exit loop;
% assemble the final output
output = 0
powerOfTen = 0
for m from 9 to 1
for i from 0 to numberOfDigits[m]
output = output + m*10^powerOfTen
powerOfTen = powerOfTen + 1
【讨论】:
这会给出错误的答案,例如89. 最佳答案是 64+25 -> 58。您的算法将产生 81+4+4 -> 229。以上是关于找到数字平方和与给定数字相加的最小整数的主要内容,如果未能解决你的问题,请参考以下文章
给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。