Fibonacci 取余问题
前言
记蓝桥入门训练第一题… 很简单的还折腾了2、3天。最后是找的学长来帮忙。感谢!
做题过程总体分为3个阶段。
先上题目:
问题描述:
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。
输入格式
输入包含一个整数n。
输出格式
输出一行,包含一个整数,表示Fn除以10007的余数。
说明:在本题中,答案是要求Fn除以10007的余数,因此我们只要能算出这个余数即可,而不需要先计算出Fn的准确值,再将计算的结果除以10007取余数,直接计算余数往往比先算出原数再取余简单。
第一阶段:
第一次提交是 最简单的递归写法,结果出来是运行超时
第二阶段:
之后 网上找了参考写法,按自己的思路写出来,结果是10个数据里只有8个正确,2个错误。
上代码:
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] numbers = new int[10008];
numbers[1] = 1;
numbers[2] = 1;
for(int i = 3; i <= 10007; i++) {
numbers[i] = (numbers[i - 1] + numbers[i - 2]) % 10007;
}
int n = sc.nextInt();
if( n >= 1 || n <= 1000000) {
n = n % 10008;
System.out.println( numbers[n] );
}else {
System.out.println(0);
}
}
}
因为前面都是正确的,只有最后2个是错,就认为这个测试数据很大,以为int类型不够装,换成了long类型,结果还是一样的。
这里提下long和int的区别:
- 早期的操作系统是16位系统,
int用二字节表示,范围是-32768~32767;
long用4字节表示,范围是-2147483648~2147483647。- 后来发展到32位操作系统,
int 用4字节表示,与long相同。- 目前的操作系统已发展到64位操作系统,但因程序编译工艺的不同,两者表现出不同的差别:
32位编译系统:int占四字节,与long相同。
64位编译系统:int占四字节,long占8字节,
long数据范围变为:-2^63 ~ 2^63-1
错误原因:
循环放数组时,不能只放 前10007个(或10008个),之后的数字还是会不一样的,题目给的提示只是放键盘输入的前n个数。
第三阶段:
正确写法:
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] numbers = new int[n];
if(n==1) // 后面输出 numbers 下标 会越界
{
System.out.print(1);
return;
}
numbers[0] = 1;
numbers[1] = 1;
for(int i = 2; i < n; i++)
{
numbers[i] = (numbers[i - 1] + numbers[i - 2]) % 10007;
//检测 取余 有没有分配率...
// System.out.print( ((numbers[i - 1] + numbers[i - 2]) % 10007)+" ");
// System.out.println( (numbers[i - 1]% 10007 + numbers[i - 2]% 10007 ) );
}
System.out.println( numbers[n-1] );
}
}
先提交的long型,后面改成int型也可以AC
这里也解决了一个疑惑点: 取余没有分配率的!!!
简单证明一下:
(a+b)% c 的结果肯定比c要小
a%c + b%c 的结果有可能比c大呀~