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

  一道普通的dp。

  首先,我们很容易想到,设$d[i][j]$是以$arr[i]$和$arr[j]$为结尾两个数的最长长度。那么状态转移就是$d[i][j]=max{d[k][i]}+1;(arr[k]+arr[i]==arr[j],k<i<j)$。那么我们可以写出类似下面这样$O(n^3)$的代码:

int d[1007][1007];

class Solution {
public:
    int lenLongestFibSubseq(vector<int>& arr) {
        int lim=arr.size();
        int ans=0;
        for (int i=0;i<lim;i++)
            for (int j=0;j<lim;j++)
                d[i][j]=0;
        for (int j=2;j<lim;j++)
            for (int i=1;i<j;i++)
                for (int k=0;k<i;k++)
                    if (arr[k]+arr[i]==arr[j]&&d[i][j]<d[k][i]+1){
                        d[i][j]=d[k][i]+1;
                        if (d[i][j]>ans)
                            ans=d[i][j];
                    }
        if (ans)
            return ans+2;
        else
            return 0;
    }
};
View Code

  但是题目要求的数据范围达到了1000,所以$O(n^3)$必然过不了。我们再来考虑优化。很明显我们可以消掉匹配对应$k$的那一层循环,主要有两个思路:

  1)因为当$i$和$j$确定时,$arr[k]$的值是已经确定了。又因为$arr[i]$的数据规模可以达到$10^9$,过大了不能直接做一个数组,所以我们用哈希表来寻找这个$k$值。又因为只有$1000$个数,出现哈希冲突的情况比较稀少,所以这样写出来的代码,一般能达到最优时间复杂度$O(n^2)$。

  2)因为题目给的数组$arr$是严格递增的,所以我们可以借助这个很不错的性质,做一个二分查找来找$k$值,时间复杂度能达到$O(n^2logn)$。

  

  我写的是哈希:

int d[1007][1007];

vector<int> Map[100003];

int Hash(long long key){
    key=(key*97+7)%100003;
    return (int)key;
}

int find(int key,vector<int>& arr){
    long long h=((long long)key*97+7)%100003;
    for (int i=0;i<Map[h].size();i++)
        if (arr[Map[h][i]]==key)
            return Map[h][i];
    return -1;
}

class Solution {
public:
    int lenLongestFibSubseq(vector<int>& arr) {
        for (int i=0;i<100003;i++)
            Map[i].clear();
        int lim=arr.size();
        int ans=0;
        for (int i=0;i<lim;i++){
            Map[Hash((long long)arr[i])].push_back(i);
            for (int j=0;j<lim;j++)
                d[i][j]=0;
        }
        for (int j=2;j<lim;j++)
            for (int i=1,to;i<j;i++){
                to=find(arr[j]-arr[i],arr);
                if (0<=to&&to<i&&d[i][j]<d[to][i]+1){
                    d[i][j]=d[to][i]+1;
                    if (d[i][j]>ans){
                        ans=d[i][j];
                    }
                }
            }
        if (ans)
            return ans+2;
        else
            return 0;
    }
};

 

 

posted @ 2022-07-09 22:45  wegret  阅读(38)  评论(0)    收藏  举报