Week6

问题描述

A sequence X_1, X_2, ..., X_n is fibonacci-like if:

  • n >= 3
  • X_i + X_{i+1} = X_{i+2} for all i + 2 <= n

Given a strictly increasing array A of positive integers forming a sequence, find the length of the longest fibonacci-like subsequence of A. If one does not exist, return 0.

(Recall that a subsequence is derived from another sequence A by deleting any number of elements (including none) from A, without changing the order of the remaining elements. For example, [3, 5, 8] is a subsequence of [3, 4, 5, 6, 7, 8].)

Example 1:

Input: [1,2,3,4,5,6,7,8]
Output: 5
Explanation:
The longest subsequence that is fibonacci-like: [1,2,3,5,8].

Example 2:

Input: [1,3,7,11,12,14,18]
Output: 3
Explanation:
The longest subsequence that is fibonacci-like:
[1,11,12], [3,11,14] or [7,11,18].

Note:

  • 3 <= A.length <= 1000
  • 1 <= A[0] < A[1] < ... < A[A.length - 1] <= 10^9
  • (The time limit has been reduced by 50% for submissions in Java, C, and C++.)

思路

这道题目主要意思就是给我们一个数列,要我们找出里面最长的斐波那契子序列(可以不连续)。这道题可以用动态规划来解决,但有一点很重要,就是 dp 数组的 i , j 在这道题目中就不能是一个区间的头和尾了,而是表示结尾两个数的下标,比如 dp[1][3] 就是表示以 A[1], A[3] 结尾的子序列。我们可以遍历 i, j,再从 j 往后找 k,看 A[k] 加入 A[i] , A[j] 结尾的数列后能否构成斐波那契数列,如果能构成斐波那契数列,则以 A[j] , A[k] 结尾的fib数列的长度 = 以A[i], A[j] 结尾的fib数列长度 + 1,即dp[j][k] = dp[i][j] + 1
在这里插入图片描述

class Solution {
public:
    int lenLongestFibSubseq(vector<int>& A) {
		
        // 数组A的大小
        int n = A.size();

        vector<vector<int>> dp(n, vector<int>(n, 0));

        // 初始的最小长度是2 (3个数才会构成一个斐波那契数列)
        int max = 2;

        // 初始化dp数组,任意两个数结尾的数列长度初始化为2
        for(int i = 0; i < n; i++){
            for(int j = i + 1; j < n; j++){
                dp[i][j] = 2;
            }
        }

        // 对以A[i],A[j]结尾的数列,从j往后找k,看A[k]加入A[i],A[j]结尾的数列后能否构成斐波那契数列
        for(int i = 0; i < n; i++){
            for(int j = i + 1; j < n; j++){
                for(int k = j + 1; k < n; k++){
                    if(A[k] == A[i] + A[j]){
                        // 如果能构成斐波那契数列,则以A[j],A[k]结尾的数列的长度 = 以A[i],A[j]结尾的数列长度+1
                        dp[j][k] = dp[i][j] + 1;
                        // 更新 max
                        if(dp[j][k] > max){
                            max = dp[j][k];
                        }
                    }
                }
            }
        }

        // 如果max还是2的话,证明不存在斐波那契子序列,则返回0
        if(max == 2){max = 0;}
        
        return max;
    }
};

这时一开始写的,但很明显会超时,A的长度最长会达到1000,而上面的代码里面有三重 for 循环,时间复杂度是 O ( n 3 ) O(n^3) O(n3)

我们可以使用map来降低时间复杂度。我们可以只遍历 j 和 k,得到 num = A[k] - A[j],判断在 j 之前是否有 A[i] == num,如果有的话,则能加长斐波那契子序列。判断 j 之前是否有 A[i] == num 可以用 map 来查找。
在这里插入图片描述

class Solution {
public:
    int lenLongestFibSubseq(vector<int>& A) {
        int n = A.size();
        // 先把每个元素都存到map里面
        map<int, int> store;
        for(int i = 0; i < n; i++){
            store[A[i]] = i + 1;  // 避免0的干扰
        }
        vector<vector<int>> dp(n, vector<int>(n, 2));
        int max = 0;
        for(int j = 0; j < n; j++){
            for(int k = j + 1; k < n; k++){
                // 查找加入A[k]是否可以构成斐波那契数列
                int num = A[k] - A[j];
                if(num >= A[j]){
                    // 因为差值都比A[j]大了,所以不可能有斐波那契数列
                    continue;
                }
                else{
                    if(store[num] != 0){ // 证明差值出现在之前的序列中
                        // 从map中取出index,然后更新dp数组
                        dp[j][k] = dp[store[num]-1][j] + 1;
                        if(dp[j][k] > max){
                            max = dp[j][k];
                        }
                    }
                }
            }
        }
        return max;
    }
};

这样写之后就不存在超时的问题了,然而新的问题出现了,Memory Limit Exceeded。

这是因为自己使用了不好的方法来判断 num 是否存在于 store 中。我首先将 A 中的每个元素都作为 store 的 key,每个 key 的 value 都是数字对应的下标+1,所以就不存在有 0 的 value了,不会影响到我后面用 store[num] 是否为 0 来判断 num 是否存在于数组中。但是每次用 if(store[num] != 0) 就会自动地把 num 加到 map 里面去,这样就会造成内存超限。所以还是要使用find,之后判断返回的迭代器是否等于 store.end()来判断 num 是否存在于 store 中。

class Solution {
public:
    int lenLongestFibSubseq(vector<int>& A) {
        int n = A.size();

        // 先把每个元素都存到map里面
        map<int, int> store;
        for(int i = 0; i < n; i++){
            store[A[i]] = i;  // 避免0的干扰
        }

        vector<vector<int>> dp(n, vector<int>(n, 2));

        int max = 0;

        for(int j = 0; j < n; j++){
            for(int k = j + 1; k < n; k++){
                // 查找加入A[k]是否可以构成斐波那契数列
                int num = A[k] - A[j];
                if(num >= A[j]){
                    // 因为差值都比A[j]大了,所以不可能有斐波那契数列
                    // 证明我们需要将j后移
                    break;
                }
                else{
                    std::map<int, int>::iterator iter = store.find(num);
                    if(iter == store.end()){continue;}
                    else{
                        dp[j][k] = dp[store[num]][j] + 1;
                        if(dp[j][k] > max){
                            max = dp[j][k];
                        }
                    }

                }
            }
        }
        return max;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值