【问题标题】:Find the number查找号码
【发布时间】:2013-06-13 08:50:18
【问题描述】:

这是一个问题陈述。

考虑一个数字 2345。如果将其数字相乘,则得到数字 120。现在,如果再次将 120 的数字相乘,则将得到数字 0,即一位数。如果我添加 2345 的数字,那么我将得到 14。如果我添加 14 的数字,那么我将得到 5,这是一个数字。

因此,任何数字都可以在一定数量的步骤中转换为两个一位数。您可以看到 2345 通过使用 2 步中的数字相乘转换为 0,并通过使用 2 步中的数字加法将其转换为 5。现在考虑任何数字 N。假设它可以通过 n1 步将数字乘以一位数字 d1 并通过 n2 步将数字与一位数字数字 d2 相加来转换。

您的任务是找到大于 N 且小于 1000000000 的最小数,可以通过在小于或等于 n1 步内将其数字乘以 d1 并在小于或等于 n2 步内将其数字与 d2 相加来转换.

如何在 C# 中解决它...

【问题讨论】:

  • 切换到 64 位系统。
  • 内存中有 10 亿个字符串肯定会导致内存不足。也许您应该只添加符合您条件的字符串?
  • 您正在创建一个包含 1000000000 个字符串的数组。当然你的内存用完了。
  • @HenkHolterman 数组被限制为 2GB 连续字节,并且引用将占用 4 个字节(或者在 64 位构建上为 8 个字节?)无论哪种方式,即使是 64 位系统也不能有数组有那么多参考资料。
  • 您已经多次问过这个问题了。这正是您遇到的确切问题,只是这一次,您需要计算步数。

标签: c# algorithm c#-2.0


【解决方案1】:

我认为您只是在错误地处理/解释问题;这是在黑暗中刺伤:

using System;
using System.Diagnostics;
static class Program
{
    static void Main()
    {
        // check our math first!

        // You can see 2345 is converted to 0 by using multiplication of digits in 2 steps
        int value, steps;
        value = MultiplyToOneDigit(2345, out steps);
        Debug.Assert(value == 0);
        Debug.Assert(steps == 2);

        // and it is converted to 5 by using addition of digits in 2 steps
        value = SumToOneDigit(2345, out steps);
        Debug.Assert(value == 5);
        Debug.Assert(steps == 2);

        // this bit is any random number
        var rand = new Random();
        for (int i = 0; i < 10; i++)
        {
            int N = rand.Next(0, MAX);
            int result = Execute(N);
            Console.WriteLine("For N={0}, our answer is {1}", N, result);
        }
    }
    const int MAX = 1000000000;
    //Now consider any number N.
    static int Execute(int N)
    {
        // Let us say that it can be converted by multiplying digits to a one digit number d1 in n1
        // steps and by adding digits to one digit number d2 in n2 steps.
        int n1, n2;
        int d1 = MultiplyToOneDigit(N, out n1),
            d2 = SumToOneDigit(N, out n2);

        // Your task is to find smallest number greater than N and less than 1000000000 
        for (int i = N + 1; i < MAX; i++)
        {
            int value, steps;

            // which can be converted by multiplying its digits to d1 in less than or equal to n1 steps
            value = MultiplyToOneDigit(i, out steps);
            if (value != d1 || steps > n1) continue; // no good

            // and by adding its digits to d2 in less than or equal to n2 steps.
            value = SumToOneDigit(i, out steps);
            if(value != d2 || steps > n2) continue; // no good

            return i;
        }
        return -1; // no answer
    }
    static int MultiplyToOneDigit(int value, out int steps)
    {
        steps = 0;
        while (value > 10)
        {
            value = MultiplyDigits(value);
            steps++;
        }
        return value;
    }
    static int SumToOneDigit(int value, out int steps)
    {
        steps = 0;
        while (value > 10)
        {
            value = SumDigits(value);
            steps++;
        }
        return value;
    }
    static int MultiplyDigits(int value)
    {
        int acc = 1;
        while (value > 0)
        {
            acc *= value % 10;
            value /= 10;
        }
        return acc;
    }
    static int SumDigits(int value)
    {
        int total = 0;
        while (value > 0)
        {
            total += value % 10;
            value /= 10;
        }
        return total;
    }
}

【讨论】:

    【解决方案2】:

    我可以看到两个内存问题;第一个是大量字符串的生成——你可能想要这样处理:

    static int SumDigits(int value)
    {
        int total = 0;
        while (value > 0)
        {
            total += value % 10;
            value /= 10;
        }
        return total;
    }
    

    完全未经测试

    第二个问题是庞大的列表;您不需要存储(在lstString 中)每个值只是为了找到最小值。只需跟踪您迄今为止所做的最好的事情。或者,如果您需要每个值的数据,那么:不要将它们存储为 string。事实上,i 可以隐含 anyway(从列表/数组中的位置),因此您真正需要的只是每个值的 cnt 值中的 int[]。而int[1000000000] 本身就是 4GB,因此在最近的 .NET 版本中需要大数组支持 (&lt;gcAllowVeryLargeObjects&gt;)。但更好的是:不要存储它。

    【讨论】:

    • byte[] 可能比int[] 更好(255 应该足够了),尽管这仍然可能不是解决问题的正确方法。
    • @Dukeling 确实,这是一种非常错误的方法;唯一“正确”的方法是从头开始,更好地理解算法想要做什么(我在单独的答案中做了)
    【解决方案3】:

    但它正在抛出 System.OutOfMemoryException

    这只是意味着您的内存不足。您的限制是1,000,000,000 或大约 1G。对于对于 32 位系统来说已经太大的字符串引用,乘以 4 个字节。即使没有实际的字符串。

    您可以将答案更紧凑地存储在 int[] 数组中,但这仍然会显示相同的问题。

    所以,降低限制或在 64 位 PC 上编译和运行。

    【讨论】:

      【解决方案4】:

      努力 :)

      现在一起做。你当然可以进行重构。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace _17082903_smallest_greatest_number
      {
          class Program
          {
              static void Main(string[] args)
              {
                  int N = 2344;
                  int n1 = 0;
                  int n2 = 0;
      
                  int d1 = SumDigits(N, ref n1);
                  int d2 = ProductDigits(N, ref n2);
      
                  bool sumFound = false, productFound = false;
      
                  for (int i = N + 1; i < 1000000000; i++)
                  {
                      if (!sumFound)
                      {
                          int stepsForSum = 0;
                          var res = SumDigits(i, ref stepsForSum);
      
                          if (res == d1 && stepsForSum <= n1)
                          {
                              Console.WriteLine("the smallest number for sum is: " + i);
                              Console.WriteLine(string.Format("sum result is {0} in {1} steps only", res, stepsForSum));
                              sumFound = true;
                          }
                          stepsForSum = 0;
                      }
      
                      if (!productFound)
                      {
                          int stepsForProduct = 0;
                          var res2 = ProductDigits(i, ref stepsForProduct);
      
                          if (res2 == d2 && stepsForProduct <= n2)
                          {
                              Console.WriteLine("the smallest number for product is: " + i);
                              Console.WriteLine(string.Format("product result is {0} in {1} steps only", res2, stepsForProduct));
                              productFound = true;
                          }
                          stepsForProduct = 0;
                      }
      
                      if (productFound && sumFound)
                      {
                          break;
                      }
                  }
      
              }
      
              static int SumDigits(int value, ref int numOfSteps)
              {
                  int total = 0;
                  while (value > 0)
                  {
                      total += value % 10;
                      value /= 10;
                  }
      
                  numOfSteps++;
      
                  if (total < 10)
                  {
                      return total;
                  }
                  else
                  {
                      return SumDigits(total, ref numOfSteps);
                  }
              }
      
              static int ProductDigits(int value, ref int numOfSteps)
              {
                  int total = 1;
                  while (value > 0)
                  {
                      total *= value % 10;
                      value /= 10;
                  }
                  numOfSteps++;
                  if (total < 10)
                  {
                      return total;
                  }
                  else
                  {
                      return ProductDigits(total, ref numOfSteps);
                  }
              }
          }
      }
      

      【讨论】:

      • 阅读问题,你需要考虑两件事一起;不是孤立的
      • 试图一起做。
      • 这里不清楚smallestStepsSum等的目的是什么;术语d1d2n1n2 在问题陈述中都有明确定义——它们不是用户变量。它们是根据N 的任何给定值精确计算得出的。
      • 重新编辑,但我看到这已经得到了回答,但无论如何。
      猜你喜欢
      • 2017-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-13
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多