C++ 找出数字平方和与给定数字相加的最小整数

C++ 找出数字平方和与给定数字相加的最小整数,c++,algorithm,performance,C++,Algorithm,Performance,示例: 输入:|输出: 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

示例:

输入:|输出:

  • 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;
 }
#包括
使用名称空间std;
int main(){
int n;
布尔发现=真;
无符号长整型和=0;
cin>>n;
int i=0;
while(找到){
++一,;
如果(n==0){//如果n=0,下面的代码就不起作用,所以我们马上给sum赋值(如果n=0)
总和=0;
打破
}
int j=i;
当(j!=0){//在每次迭代之后,j的最后一个数字被剥离(j/=10),所以我们希望在j变为0时立即停止
sum+=(j%10)*(j%10);//每次迭代后,sum增加*(j的最后一位)^2*(j%10)获得j的最后一位
j/=10;
}
如果(sum==n){//如果我们满足问题的要求,那么j的每个数字的平方和等于给定的数字n,循环中断,我们得到结果
打破
}
sum=0;//否则,sum将为null,循环将重新开始
}

可以使用动态规划。如果我们知道最优解的第一位数字,那么剩余的将是和的剩余部分的最优解。因此,我们可以猜测第一位数字,并对较小的目标使用缓存计算来获得最优值

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]
(编辑)此答案不正确。贪婪方法不适用于此问题-抱歉。

我将以一种与语言无关的方式给出我的解决方案,即算法。 我还没有测试过,但我相信这应该可以做到,复杂性与输出中的位数成正比:

   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
       }
     }

   }

让我们试着解释大卫的解。我相信他的假设是,给定一个最优解,
abcd…
n-a^2
的最优解将是
bcd…
,因此,如果我们计算从
1
n
的所有解,我们可以依赖以前的解来计算小于
n的数当我们尝试不同的减法时

那么我们如何解释大卫的代码呢

(1) 将数字1到n的解决方案按顺序放入表
最佳

for i in range(1, n+1):
    best.append(...
(2) 如果从
i
中减去
d^2
是可行的,则当前查询的解决方案
i
d
不同数字选择数组中的最小值,介于
1
9
之间

转换为整数的最小值

min(int(
…字符串
d
,与先前记录在表中的
n-d^2
的解决方案字符串连接(删除零的解决方案连接):

让我们修改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)

当我们到达
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'      ) ])

诸如此类。

这实际上是一个众所周知的伪装问题。在这个问题中,你得到一笔钱,并被要求用最少数量的硬币支付。在这里,我们有81、64、49、36、…、1美分,而不是1美分、5美分、1美分和1美分

显然,这是一个鼓励动态规划的典型例子。在动态规划中,与递归方法不同,递归方法要求您从上到下,现在要求您从下到上,并“记忆”稍后需要的结果。因此…速度要快得多

这是我在JS中的方法,它可能和David的方法有着非常相似的工作

函数getMinNumber(n){ var sls=数组(n).fill(), sct=[],最大值; sls.map((u,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.lengthconsole.log(getMinNumber(500));
您的问题没有被很好地解决。例如,您可以说
任意数字->1111111…1111
。这将是一个简单但正确但有效的解决方案。我想您必须回到公式化阶段。问题说明“找出数字平方和与给定数字相加的最小整数"我的错,你是对的!这个问题比它看起来有趣得多,而且可能应该更好地定值。我建议在问题的正文中完整地陈述这个问题,而不是依赖于问题的标题。我的基本原理是将
n
除以
81
,以获得
9
的数量。然后取剩余数,除以
64
,这是
8
,依此类推……注意,结果中所有数字的排列都具有相同的性质。因此,一个可能的解决方案是找到我刚开始竞争编程的最小完美平方集合,所以动态规划是一个顶级问题我还没有发现ic。你能给代码添加一些解释,这样它就不那么深奥,更容易理解了吗?谢谢lot@RafaelSofi-Zadeh有很多教程。也许你应该从那开始。@Rafael Sofi Zadeh我会建议你,我相信它会很快给你一个关于动态编程的想法。这个将给出错误的答案,例如89。最佳答案是64+25->58。您的算法将产生81+4+4->229。
=> [0, 1, 11, 111, 2, 12, 112, 1112, 22, 3, 13]
   min([ int(str(1) + str(best[5 - 1])), int(str(2) + str(best[5 - 4])) ])
=> min([ int(   '1'   +     '2'       ), int(   '2'   +     '1'      ) ])