剑指 Offer 10- I. 斐波那契数列

简介: 剑指 Offer 10- I. 斐波那契数列

剑指 Offer 10- I. 斐波那契数列


题目:


写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:


斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。


答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。


范围: 0 <= n <= 100 的整数


一想到求斐波那契,就想到递归,啪,然后超时,因为递归效率实在太低,虽然代码简洁


所以递归不行,只能使用循环.

public static int fib(int n) {
    if (n < 2) return n;
    return fib(n - 1) + fib(n - 2);
}

还有个问题,就是还需对结果进行1000000007取余,且往后结果远大于2的32次方,当然也会大于2的64次方,int和long都不够存储.


但是还有 BigDecimal,网上查了下据说可以存上千位的数,这十几二十位的数,当然小问题啦。


第100个斐波那契数:354,224,848,179,261,915,075


2的64次方: 18,446,744,073,709,551,616


方式一:使用BigDecimal数组


注意:1.数组长度可以动态定义,如果只需要第一项,却去定义长度100,多余


2.int类型转 BigDecimal类型 BigDecimal.valueOf(1)


3.相加用 add方法


4.divideAndRemainder 进行取余


返回一个数组: result[0]为商,result[1]为余


BigDecimal类型 转为 int类型 .intValue()

public static int fib1(int n) {
    int mod = 1000000007;  //取余
    int len = 101;
    BigDecimal[] arr = new BigDecimal[n+1];
    arr[0] = BigDecimal.valueOf(0);
    arr[1] = BigDecimal.valueOf(1);
    //只计算到 arr[n]
    for (int i = 2; i < (n + 1); i++) {
        arr[i] = arr[i - 1].add(arr[i - 2]);  //add 相加
    }
    //divideAndRemainder 返回一个数组: result[0]为商,result[1]为余
    BigDecimal[] result = arr[n].divideAndRemainder(BigDecimal.valueOf(mod));
    return result[1].intValue(); //转为int返回
}

方式二:以减代取余 –>减法比取余效率更高


每当下一项大于1000000007时,就减去1000000007,所以即使最后相加,也不可能会产生大于两倍1000000007的数.这点很重要


初始化的int数组,所有项默认为0,所以


//arr[0] = 0; //可省–>默认值为0

public static int fib(int n) {
    int mod = 1000000007;  //取余
    int[] arr = new int[n + 1];
    //arr[0] = 0;  //可省-->默认值为0
    arr[1] = 1;
    for (int i = 2; i < (n + 1); i++) {
        arr[i] = arr[i - 1] + (arr[i - 2]);
        //每当下一项大于mod时,减去mod,即相当于进行取余操作,以减法代替取余 效率更高
        if (arr[i] > mod) {
            arr[i] -= mod;
        }
    }
    return arr[n];
}

方式三:以数组存储了并不需要的数,因为每次只需要第n个数,不需要对之前的结果进行存储. 以while 循环

public static int fib(int n) {
    if (n < 2) return n;
    int mod = 1000000007;  //取余
    int f = 0;  //first
    int s = 1;  //second
    int result = 0;  //初始化结果
    while (--n > 0) {
        result = f + s;
        if (result > mod) result -= mod;
        f = s;
        s = result;
    }
    return result;
}


结果:

执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户

内存消耗:35 MB, 在所有 Java 提交中击败了90.07% 的用户

通过测试用例:51 / 51

相关文章
|
6月前
剑指 Offer 10- I:斐波那契数列
剑指 Offer 10- I:斐波那契数列
34 1
|
6月前
剑指 Offer 10- II:青蛙跳台阶问题
剑指 Offer 10- II:青蛙跳台阶问题
48 1
|
6月前
剑指 Offer 49:丑数
剑指 Offer 49:丑数
35 0
|
6月前
剑指 Offer 07:重建二叉树
剑指 Offer 07:重建二叉树
32 0
|
6月前
|
Java C++ Python
剑指 Offer 58 - II:左旋转字符串
剑指 Offer 58 - II:左旋转字符串
62 0
|
C++ 容器
剑指 Offer 58 - II. 左旋转字符串(3种方法)
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。 请定义一个函数实现字符串左旋转操作的功能。 比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
68 0