剑指 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]为余

  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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦中千秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值