【问题标题】:Find minimum number of digits required to make a given number查找生成给定数字所需的最小位数
【发布时间】:2020-11-28 11:08:53
【问题描述】:

我们必须找到生成给定数字所需的最小位数,例如:14 => 95 (9 + 5 = 14) 是两位数,这是形成 14 的最小值。

int moves(int n) {

    int m = 0;            // Minimum count

    while (n-9 >= 0) {    // To place maximum number of 9's
        n -= 9;
        m++;
    }

    if (n == 0) {         // If only nines made up the number
        return m;
    }

    else {
        m++;
        return m;
    }
}

我收到了一位在线法官的 TLE(超出运行时间限制)。我该如何改进它或有更好的方法?

【问题讨论】:

  • 它似乎工作正常。即使将2^31-1 分配给n,使用g++ -std=c++14 -O2 仍不超过0.1 秒。
  • 不需要循环。查找 mod 运算符。
  • 这能回答你的问题吗? Finding the number of digits of an integer
  • 在 O(1) 中与您的结果相同的函数体:return n/9 + (n % 9 == 0 ? 0 : 1);
  • 你需要a = floor(n/9) 9,和数字n-9a

标签: c++ c++14


【解决方案1】:

您的解决方案运行良好。你可以试试更短的:

return (n%9==0)? n/9 : n/9 +1 ;

较短,但不太容易阅读...

或妥协:

if (n%9==0) // n can be divided by 9
   return n/9;
else
   return n/9+1;

【讨论】:

  • 这个答案显示了更高效的代码,但没有解释它的好处。是的,代码更短,但更重要的是,它通过将 O(n) 循环转换为 O(1) 算术运算和分支,解决了导致超出时间限制 (TLE) 错误的 OP 效率问题。未能通过 TLE 的代码不能“正常工作”——它可能“正确但效率低下”。
【解决方案2】:

正如您所猜测的,您需要将较小的数字迭代到较大的数字,例如 111119 很好,但我们想要最小的数字...您的答案是错误的。最低的是 59!

您可以使用蛮力,但它会起作用,但对于更大的数字,您会遇到困难,因此您需要先猜测:我需要多少个最小数字才能找到我的解决方案?

例如,如果您想找到 42,只需添加所需的 9 即可溢出结果! 9 + 9 + 9 + 9 + 9 = 45。当你发现溢出时,你知道答案低于99999。

现在我需要减少多少值才能得到正确答案,如预期的那样为 3?

所以 99996、99969 等......将是有效的!但是你想降低,所以你必须降低最大的单位(当然是左边的!)。

答案是 69999 = 42!

int n = 14;
int r = 0;

for (int i = i; i < 10 /*if you play with long or long long*/; i++)
   if (i * 9 >= n)
   {
       for (int j = 0; j < i; j++)
           r = r * 10 + 9;
       while (is_correct(r, n) == false)
       {
           // Code it yourself!!
       }
       return (r);
   }

现在它正确地返回真或假。你可以让它返回 r 实际上是减少你需要减少的数字!这不是最快的方法,而且总是有更快的方法,用二进制移位,但这个算法可以正常工作!

【讨论】:

    【解决方案3】:

    说明

    我们知道每个数字a 都可以表示为 (a_n * 10 ^ n) + ... + (a_2 * 10 ^ 2) + (a_1 * 10) + (a_0) 其中a_k 是数字

    10^n = 11...11 * 9 + 1(n 位 1)。

    表示数字 10^n 可以表示为 11...11 + 1 个数字的总和。

    现在我们可以把a写成(a_n * 11..11 * 9 + a_n) + ...

    按 9 分组后(帮助,我不知道这个的英文术语。Factoring?(a_n * 11..11 + a_n-1 * 11..11 + ... a_1) * 9 + (a_n + a_n-1 + ... + a_1 + a_0) 我会写成b_9 * 9 + b_1

    这意味着数字a可以表示为b_9数字9的总和+b_1需要多少(顺便说一下,这是递归的)

    概括一下:

    让我们调用函数 f

    • 如果 -10

    • 需要两个计数器,c1c2

    • 遍历数字

    • 对于每个ith 数字,乘以i 数字编号11..11 并将结果添加到c1

    • ith 数字添加到c2

    • 结果是c_1 + f(c_2)

    为了练习,请以非递归方式实现。

    【讨论】:

      【解决方案4】:

      您的代码首先查看 9 与该数字匹配的次数。这可以更轻松地完成:

      int m = n/9;
      

      这就足够了,因为我们进行了整数除法,其中余数被丢弃。请注意,如果 n 将是 float 或其他浮动类型,则这将不起作用。

      剩下的问题是它是否能被 9 整除。如果没有,我们有一个额外的数字。这可以通过模运算符来完成(为了便于理解,它变得冗长):

      bool divisible_by_nine = (n % 9 == 0);
      

      假设您可能不知道取模运算符,它会返回整数除法的余数,即 47 % 9 = 2,因为 47 / 9 = 5 余数 2。

      没有它,你会去

      int remainder = n - 9*m;
      bool divisible = (remainder == 0);
      

      综合:

      int required_digits(int number)
      {
         bool divisible = (number % 9 == 0);
         return number/9 + (divisible ? 0 : 1);
      }
      

      或在一行中,具体取决于您希望它的详细程度:

      int required_digits(int number)
      {
         return number/9 + (number % 9 == 0 ? 0 : 1);
      }
      

      由于没有任何循环,因此它在 Θ(1) 中,因此应该在您要求的时间限制内工作。

      (从技术上讲,处理器也可以像您在内部处理的那样处理除法,但这样做非常有效。为了绝对正确,我必须添加“假设除法是一个恒定时间操作”。 )

      【讨论】:

        猜你喜欢
        • 2010-12-07
        • 1970-01-01
        • 2017-03-23
        • 2021-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-02
        • 2021-08-14
        相关资源
        最近更新 更多