【问题标题】:Product of two consecutive Fibonacci numbers - code times out两个连续斐波那契数的乘积 - 代码超时
【发布时间】:2019-06-29 03:33:04
【问题描述】:

我正在尝试解决 Java Codewars 上连续 Fib 数字的乘积。 示例测试运行良好,但是当我单击尝试时,它会超时。

我的错误可能是什么?

你可以在这里找到任务详情:https://www.codewars.com/kata/product-of-consecutive-fib-numbers

public class ProdFib { 
public static long[] productFib(long prod) {

int a = 0;
int ta, ta2= 0;
int a2 = 1;

while (a * a2 <= prod){
    ta = a;
    ta2 = a2;
    a2 = a + a2;
    a = ta2;

    if(a * a2 == prod){
    long[] re = new long[]{a,a2,1};
    return re;
    }
    if(a * a2 > prod){
    long[] re = new long[]{a,a2,0};
    return re;
    }
}
return null;
   }
 }

【问题讨论】:

  • "示例测试运行良好" - 请在您的代码中显示。 “当我点击尝试” - 不知道这是什么意思
  • 你知道代码战使用的测试输入吗?
  • 它针对完整的测试套件运行我的代码,所以基本上 2 个测试运行成功,其他测试超时
  • @DávidKatona 当你使用这个时会发生什么:ideone.com/RQVeCR,这是我根据你的方法制作的缩小版
  • public void test1() { long[] r = new long[] {55, 89, 1}; assertArrayEquals(r, ProdFib.productFib(4895));

标签: java timeout fibonacci


【解决方案1】:

您的问题是您将变量定义为int 而不是long

如果您尝试使用 prod 44361286907595736L 运行程序,它将进入无限循环。原因是当你将两个ints 相乘时,结果也是一个int。该产品是 165580141 和 267914296 相乘的结果。这些是合法的整数,但是当您将它们相乘时,这个数字对于整数溢出来说太大了。所以你得到的数字远低于44361286907595736L。并且您的循环不会停止。

如果您将变量定义为long,则不会发生这种情况。这是您的程序的可读性稍强的版本。

public static long[] productFib(long prod) {

    long prev = 0;
    long curr = 1;
    long multiplied = prev * curr;

    while (multiplied < prod) {
        long temp = curr;
        curr += prev;
        prev = temp;
        multiplied = prev * curr;
    }

    return new long[] { prev, curr, multiplied == prod ? 1 : 0 };

}

【讨论】:

    【解决方案2】:

    问题定义: 输入:product - 想要的产品 输出:3 个元素的数组: {F1,F2,结果}

    其中 F1 是第一个斐波那契数, F2 是第二个斐波那契数, 如果 F1 * F2 = 产品,则结果等于 1, 否则:结果 = 0

    使用以下公式可以更有效地解决此问题: 1. 获得第n个斐波那契数的直接公式。 2. 获取给定斐波那契数索引的直接公式。

    您可以在以下链接中获取相关公式和解释:https://en.wikipedia.org/wiki/Fibonacci_number

    思路是获取斐波那契数的索引:sqrt(product)

    然后我们可以得到下一个和上一个斐波那契数,并将它们的产品与给定的产品进行比较

    这是相关的Java代码:

    private static double phi = (1 + Math.sqrt(5)) / 2;
    
    public static void main(String[] args) { 
      System.out.println(Arrays.toString(fibProd(800))); // [34, 55, 0]
      System.out.println(Arrays.toString(fibProd(714))); // [21, 34, 1]
      System.out.println(Arrays.toString(fibProd(15))); // [3, 5, 1]
      System.out.println(Arrays.toString(fibProd(40))); // [5, 8, 1]
      System.out.println(Arrays.toString(fibProd(2))); // [1, 2, 1]
      System.out.println(Arrays.toString(fibProd(3))); // [2, 3, 0]
    }
    
    private static long[] fibProd(long product) {
        long currentIndex = getFibIndex(Math.round(Math.sqrt(product)));
        long currentElement = getFibElement(currentIndex);
        long previousElement = getFibElement(currentIndex - 1);
        long nextElement = getFibElement(currentIndex + 1);
    
        int c1 = Long.compare(previousElement * currentElement, product);
    
        if(c1 == 0) {
            return new long[] {previousElement, currentElement, 1};
        }
    
        int c2 = Long.compare(currentElement * nextElement, product);
    
        if(c2 == 0) {
            return new long[] {currentElement, nextElement, 1};
        }
    
        if (c1 < c2) {
            return new long[] {currentElement, nextElement, 0};
        } else {
            return new long[] {previousElement, currentElement, 0};
        }
    }
    
    private static long getFibIndex(long item) 
    { 
        double m = item * Math.sqrt(5) + 0.5;
        return Math.round(Math.log(m) / Math.log(phi));
    }
    
    private static long getFibElement(long index) {
        return Math.round(Math.pow(phi, index)  / Math.sqrt(5)); 
    }
    

    【讨论】:

      【解决方案3】:

      试试这个

      public class ProdFib {
      public static long[] productFib(long prod) {
          int i = 0;
          int f1 = 0;
          int f2 = 0;
          while ((f(i) * f(i + 1) != prod && f(i) * f(i + 1) < prod)) {
              i += 1;
              f1 = f(i);
              f2 = f(i + 1);
          }
          if (f1 * f2 == prod)
              return new long[] { f1, f2, 1 };
          else
              return new long[] { f1, f2, 0 };
      }
      
      public static int f(int i) {
          if (i == 0) {
              return 0;
          }
          if (i == 1) {
              return 1;
          }
          return f(i - 2) + f(i - 1);
      }
      
      public static void main(String[] args) {
          long[] r = productFib(1000);
          System.out.println(r[0] + " " + r[1] + " " + r[2]);
      }
      

      }

      【讨论】:

      • 您在每次迭代中运行递归函数六次。这个算法的效率是可怕的,尤其是每次迭代的数字都保持不变。
      • @Lino 是的,我什至没有计算函数本身内部的调用。
      • @RealSkeptic 哦,我错过了 while-body 中的那些,所以它可能至少有 12 个调用......不是最高效的方式
      猜你喜欢
      • 2018-01-25
      • 1970-01-01
      • 2014-11-28
      • 1970-01-01
      • 2010-09-22
      • 1970-01-01
      • 1970-01-01
      • 2022-10-18
      • 1970-01-01
      相关资源
      最近更新 更多