查找其数字平方和与给定数字相加的最小整数

Find the smallest integer whose sum of squares of digits add to the given number

本文关键字:数字 整数 查找      更新时间:2023-10-16

示例:

输入: | 输出:

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

我正在寻找问题的快速解决方案。

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

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]

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

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

(1(将数字1到n的解按顺序放在表best中:

for i in range(1, n+1):
    best.append(...

(2( 当前查询的解决方案 i 是不同数字(d 19 之间的选择数组中的最小值,如果从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的选择是12,因此选择数组是:

   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 美分,而不是一

、镍、硬币和四分之一。

显然,这是鼓励动态编程的典型示例。在动态编程中,与递归方法不同,在递归方法中,您应该从上到下,现在应该从下到上并"记住"以后需要的结果。因此。。。快多了..!

所以好的,这是我在 JS 中的方法。它可能与大卫的方法非常相似。

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 的查找数组。这就是记忆发生的地方。然后从1n开始,我们将在几个选项中映射最佳结果。例如,如果我们要查找10的分区,我们将从 10 平方根的整数部分 3 开始,并将其保留在 max 变量中。所以 3 是其中一个数字,另一个应该是 10-3*3 = 1。然后我们查找先前求解的1,它实际上是在 sls[0][1]的,并将 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 的位置。

(编辑( 这个答案是不正确的。贪婪的方法对这个问题不起作用 - 对不起。

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

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