斐波那契数Fibonacci

509. 斐波那契数

斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。

示例 1:

输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1.
示例 2:

输入:3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2.
示例 3:

输入:4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3.

提示:

0 ≤ N ≤ 30

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fibonacci-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

递归解法(Recursive)

// 时间复杂度 2^n,空间复杂度n
class Solution {
    public int fib(int N) {
        if (N < 2) return N;
        return fib(N - 1) + fib(N - 2);
    }
}

迭代(Iterative)

// 时间复杂度 n ,空间复杂度 1
class Solution {
    public int fib(int N) {
        if (N <= 1) return N;
        int a = 0, b = 1;
        while (N -- > 1) {
            int sum = a + b;
            a = b;
            b = sum;
        }
        return b;
    }
}

由顶到下,递归(Dynamic Programming - Top Down Approach)

// 时间复杂度降为n,空间为n
class Solution {
    int[] cache = new int[31];
    public int fib(int N) {
        if (N <= 1) return N;
        else if ( cache[N] != 0) return cache[N];
        else return cache[N] = fib(N - 1) + fib(N - 2);
    }
}

由下到上,计算到要求的值(Dynamic Programming - Bottom Up Approach)

//时间复杂度n,空间复杂度n
class Solution {
    public int fib(int N) {
        if (N<=1) return N;
        return memoize(N);
    }
    public int memoize(int n){
        int[] cache = new int[n+1];
        cache[1] = 1;
        for (int i=2;i <= n;i++) {
            cache[i] = cache[i-1] + cache [i-2];
        }
        return cache[n];
    }
}

873. 最长的斐波那契子序列的长度

如果序列 X_1, X_2, ..., X_n 满足下列条件,就说它是 斐波那契式 的:

n >= 3
对于所有 i + 2 <= n,都有 X_i + X_{i+1} = X_{i+2}
给定一个严格递增的正整数数组形成序列,找到 A 中最长的斐波那契式的子序列的长度。如果一个不存在,返回 0 。

(回想一下,子序列是从原序列 A 中派生出来的,它从 A 中删掉任意数量的元素(也可以不删),而不改变其余元素的顺序。例如, [3, 5, 8] 是 [3, 4, 5, 6, 7, 8] 的一个子序列)
示例 1:

输入: [1,2,3,4,5,6,7,8]
输出: 5
解释:
最长的斐波那契式子序列为:[1,2,3,5,8] 。
示例 2:

输入: [1,3,7,11,12,14,18]
输出: 3
解释:
最长的斐波那契式子序列有:
[1,11,12],[3,11,14] 以及 [7,11,18] 。

提示:

3 <= A.length <= 1000
1 <= A[0] < A[1] < ... < A[A.length - 1] <= 10^9
(对于以 Java,C,C++,以及 C# 的提交,时间限制被减少了 50%

思路

//思路1:两遍正序遍历+二分查找(或set)时间为O(N^2logN)
//不能用二分查找,需要找到两数之和之后循环查找,所以用HashSet

//思路2:动态规划,倒着推,状态转移方程最后第三个数到最大序列等于第二个加1
//再用hashMap存数据的,value为保存数据的索引,方便longest通过索引确定保存最大值的key

solution1

//时间复杂度为 O(n^2 log M)
class Solution {
    public int lenLongestFibSubseq(int[] A) {
        Set<Integer> s = new HashSet();
        for (int i : A) s.add(i);
        int len = A.length, ans = 0;

        for (int i = 0; i < len; i++){
            for (int j = i + 1; j < len; j++){
                int a = A[j], b = A[i] + A[j];
                if (b > A[len-1]) break;
                int count = 2;
                while(s.contains(b)){
                    int temp = b;
                    b += a;
                    a = temp;
                    ans = Math.max(ans,++count);
                }
                
            }
        }
        return ans >= 3 ? ans:0;
    }
}

solution2

class Solution {
    public int lenLongestFibSubseq(int[] A) {
        Map<Integer,Integer> map = new HashMap();//保存原数组
        Map<Integer,Integer> longest = new HashMap();//保存最大子序列,(k,i,j)key=k*len+i
        int len = A.length, ans = 0;

        for (int i = 0; i < len; ++i)
            map.put(A[i], i);
        for (int i = 0; i < len - 1; i++){
            for (int j = i + 1; j < len; j++){
                int mapk = A[j] - A[i];
                int k = map.getOrDefault(A[j] - A[i], -1); //用map.get同时判断是否存在的一种方式
                if (k >= 0 && k < i){
                    int count = longest.getOrDefault(k*len+i,2) + 1;//获取值默认为2,再加1
                    longest.put(i*len+j,count);
                    ans = Math.max(ans, count);
                }
                
            }
        }
        return ans >= 3 ? ans:0;
    }
}
posted @ 2020-05-14 17:32  gg12138  阅读(485)  评论(0编辑  收藏  举报