projecteuler No.104 Pandigital Fibonacci ends

来源:互联网 发布:网络侠义游戏辅助论坛 编辑:程序博客网 时间:2024/05/21 17:02

题目链接:

Problem 104 Pandigital Fibonacci ends

题目104:找出前九位和后九位数字为pandigital的斐波那契数。

通过人数:8537


题目分析:

这道题就是从斐波那契数列中选择最小的符合条件的项。由于涉及的数比较大,考虑利用java的高精度类。

我最初的代码是这样的:

BigInteger F[] = new BigInteger[100000];F[1] = new BigInteger("1");F[2] = new BigInteger("1");outer:for (int i = 3; i < 100000; i++){F[i] = F[i-1].add(F[i-2]);if (i%100 == 0)System.out.print(i+"\n");if (i > 57000){int mark[] = new int[10];String temp = F[i].toString();for (int j = 0; j < 9; j++)mark[temp.charAt(j) - '0']++;for (int j = 1; j <= 9; j++)if (mark[j] != 1)continue outer;for (int j = 1; j <= 9; j++)mark[temp.charAt(temp.length() - j) - '0']--;for (int j = 1; j <= 9; j++)if (mark[j] != 0)continue outer;System.out.print(F[i]);break;}}

单纯地计算斐波那契数列F[]并将其转化为字符串再检查题目所需的要求。

但是发现在10000以内没有满足题目要求的,在10000以上就算得非常慢...算100000要几十分钟的时间。

再检查代码,发现是BigInteger.toString算得太慢了。看来BigInteger使用的是2进制进行内部存储,而高精度的进制转换差不多O(n^2)的时间复杂度(n为有效位数),实在是占用了太多的时间。

然后考虑到,如果只需要检测后9位,就只需要在运算时保留后9位就好了。而检测前9位的时候,考虑到a+b=c中,a,b有一定百分率的误差后,c的误差百分率不超过a,b的最大值。而这要是想要影响到结果的前几位,只有误差产生进位和退位并影响到前面很多位时才会发生。而这种事件的发生概率,随着精度每增加一位(即误差减少十倍),就会减少10倍。只要多保留10位的精度,在若干万的测试数据中就很难会遇到了。(尤其是斐波那契数列的数位排列还几乎是随机的...)于是我就用另一个数组保留斐波那契数列的前十几位。这样前9位就有极大的概率是准确的了。


解题过程:

一、常量及初始化:

BigInteger N = new BigInteger("1000000000");BigInteger NN = new BigInteger("1000000000000000");BigInteger F[] = new BigInteger[1000000];F[1] = new BigInteger("1");F[2] = new BigInteger("1");BigInteger G[] = new BigInteger[1000000];G[1] = new BigInteger("1");G[2] = new BigInteger("1");
数列F计算尾数,G计算首数。N用来让F去模,NN用来控制G的精度。


二、数列求值:

outer:for (int i = 3; i < 1000000; i++){F[i] = F[i-1].add(F[i-2]);G[i] = G[i-1].add(G[i-2]);if (F[i].compareTo(N) > 0)F[i]=F[i].remainder(N);if (G[i].compareTo(NN) > 0){G[i] = G[i].divide(BigInteger.TEN);G[i - 1] = G[i - 1].divide(BigInteger.TEN);}
即使如上所述地对F和G均保留斐波那契数列的部分位。


三、筛选:

int m[] = new int[10];String s1 = F[i].toString();if (s1.length() < 9)continue;for (int j = 0; j < 9; j++)m[s1.charAt(j) - '0']++;for (int j = 1; j <= 9; j++)if (m[j] != 1)continue outer;String s2 = G[i].toString();if (s2.length() < 9)continue;for (int j = 0; j < 9; j++)m[s2.charAt(j) - '0']--;for (int j = 1; j <= 9; j++)if (m[j] != 0)continue outer;System.out.print(i+"\n");
这段也没什么可说的了,考察F[i]和G[i]的后9位和前9位。排除掉不满足条件的,剩下的就是满足条件的了。最后输出329468。



分析:其实也可以直接写一个基于10进制的高精度整数类。这样转string就会快很多...不过用BigInteger不就是因为偷懒么~O(∩_∩)O~




以上只是我做题时的解法。

如果有更好的解法、更好的思路,欢迎评论讨论~O(∩_∩)O~

0 0
原创粉丝点击