【问题标题】:Project Euler #119 Make Faster欧拉计划 #119 加快速度
【发布时间】:2015-01-23 02:09:00
【问题描述】:

尝试解决 Project Euler 问题 119:

数字 512 很有趣,因为它等于其数字之和的某个幂:5 + 1 + 2 = 8,并且 8^3 = 512。具有此属性的数字的另一个示例是 614656 = 28 ^4.

我们将定义 an 为这个序列的第 n 项,并坚持一个数字必须至少包含两位数字才能有和。

给定 a2 = 512 和 a10 = 614656。

找到a30。

问题:有没有比只检查每个数字直到找到 a30 更有效的方法来找到答案?


我的代码

    int currentNum = 0;
    long value = 0;
    for (long a = 11; currentNum != 30; a++){ //maybe a++ is inefficient
        int test = Util.sumDigits(a);
        if (isPower(a, test)) {
            currentNum++;
            value = a;
            System.out.println(value + ":" + currentNum);
        }
    }
    System.out.println(value);

isPower 检查 a 是否是检验的幂。 Util.sumDigits:

    public static int sumDigits(long n){
        int sum = 0;
        String s = "" + n;
        while (!s.equals("")){
            sum += Integer.parseInt("" + s.charAt(0));
            s = s.substring(1);
        }
        return sum;
    }

程序已经运行了大约 30 分钟(长时间可能会溢出)。输出(到目前为止):

81:1

512:2

2401:3

4913:4

5832:5

17576:6

19683:7

234256:8

390625:9

614656:10

1679616:11

17210368:12

34012224:13

52521875:14

60466176:15

205962976:16

612220032:17

【问题讨论】:

  • 子串部分一定是杀手...
  • @gangqinlaohu 唯一知道的方法就是分析它。其他一切都只是猜测。根据您的猜测,a++ 可能是您真正需要获取一些数据的问题。字符串操作通常比数学更昂贵。真正的改进将在于算法,减少必要的迭代次数,而不是单个操作的成本。
  • maybe ++a is inefficient -- 这听起来真像个笑话。
  • Project Euler 解决方案应该在一分钟内完成。您已经实施了看起来很幼稚的解决方案,现在寻找更聪明的解决方案。没有Java调整会有所帮助。先重新思考数学,然后重新思考代码。
  • 当您迭代时,总和每次都会增加一,但十的倍数除外。

标签: java performance


【解决方案1】:

解决方案是一个 15 位数字。祝你好运,优化求和,使其运行得足够快,可以检查每个数字。

转过头来解决问题。数字之和是一个比较小的数(最大为9×数字中的位数),幂也会比较低(即使是很小的数也不需要很大的幂就可以提升到15位数) .

所以循环总和和幂,计算总数(您可以在内部循环中保持一个运行总数,乘以,甚至不需要幂计算),然后将其数字相加,看看它是否与您的循环匹配变量。

数字不会按顺序排列,因此请计算超出您需要的数量并对结果进行排序。

应该在大约一秒钟后运行。

【讨论】:

    【解决方案2】:

    关于这个数字总和......这里有一些确凿的事实:

     0% Scenario{vm=java, trial=0, benchmark=NaiveDigitSum} 542.90 ns; σ=11.00 ns @ 10 trials
    50% Scenario{vm=java, trial=0, benchmark=BetterDigitSum} 42.13 ns; σ=1.42 ns @ 10 trials
    
         benchmark    ns linear runtime
     NaiveDigitSum 542.9 ==============================
    BetterDigitSum  42.1 ==
    

    测试代码:

    import com.google.caliper.Runner;
    import com.google.caliper.SimpleBenchmark;
    
    public class Performance extends SimpleBenchmark {
      public void timeNaiveDigitSum(int reps) {
        for (int r = 0; r < reps; r++) sumDigits(r + 1_000_000);
      }
      public void timeBetterDigitSum(int reps) {
        for (int r = 0; r < reps; r++) sumDigitsBetter(r + 1_000_000);
      }
      public static int sumDigits(long n){
        int sum = 0;
        String s = "" + n;
        while (!s.equals("")){
            sum += Integer.parseInt("" + s.charAt(0));
            s = s.substring(1);
        }
        return sum;
      }
      static int sumDigitsBetter(long n) {
        int sum = 0;
        for (; n != 0; sum += n % 10, n /= 10);
        return sum;
      }
      public static void main(String... args) {
        Runner.main(Performance.class, args);
      }
    }
    

    (剧透解决方案已删除,可通过编辑历史获得)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多