每日一题·873.最长的斐波那契子序列的长度.记忆化搜索

力扣

题目

 

示例

 

思路

求斐波那契数列

我们可以枚举斐波那契数列的前两项,然后判断数组中是否有第三项即可。但是这样子时间开销非常大,会超时,所以我们用空间换时间法

在上面方法中我们可能会重复计算某些元素,如计算1,2,3,5,8时,已经计算了2,3,5,8的长度,我们设res[i][j]表示以arr[i],arr[j]开头的斐波那契数列的最长个数。

在计算时,如果已经计算过res[i][j]则直接返回即可。

从而到达空间换时间

在寻找第三项时可以枚举每一个元素,当时太浪费时间,我们可以用hash保存数组每一个元素对应的下标,也可以将枚举换为二分查找,因为数组是严格的升序,所以第三项严格来说,最多只存在一个

其实我们申请的记忆化数组只用了一半,还可以再压缩,留给个位了

代码


#define MAX(a , b) ((a) > (b) ? (a) : (b))
/*
*int dfs(int * arr, int arrSize, int inode, int jnode, int ** res)
int dfs:递归搜索第三项
int * arr:数组
int arrSize:数组长度
int inode:第一项下标
int jnode:第二项下标
int ** res:记忆数组
返回值:斐波那契序列长度
*/

int dfs(int * arr, int arrSize, int inode, int jnode, int ** res)
{
    if(res[inode][jnode] > 0)//之前计算过了
    {
        return res[inode][jnode];
    }
    res[inode][jnode] = 2;
    int mid;
    int left = jnode;
    int right = arrSize-1;
    while(left <= right)//二分搜索第三项,hash更简单
    {
        mid = (left + right) / 2;
        if(arr[mid] == (arr[inode] + arr[jnode]))//找到了唯一的第三项
        {
            res[inode][jnode] = 1 + dfs(arr, arrSize, jnode, mid, (int **)res);
            break;
        }
        else if(arr[mid] > (arr[inode] + arr[jnode]))
        {
            right = mid - 1;
        }
        else
        {
            left = mid + 1;
        }
    }
    return res[inode][jnode];
}
/*
*int lenLongestFibSubseq(int* arr, int arrSize)
int lenLongestFibSubseq:求数组中最长的斐波那契数列最长子序列
int* arr:数组
int arrSize:数组长度
返回值:最长斐波那契数列
*/

int lenLongestFibSubseq(int* arr, int arrSize){
    int ** res = malloc(sizeof(int*) * arrSize);//申请额外空间
    int i, j;
    for(i = 0; i < arrSize; i++)//初始化
    {
        res[i] = malloc(sizeof(int) * arrSize);
        memset(res[i], 0, sizeof(int) * arrSize);
    }
    int max = 0;
    for(i = 0; i < arrSize; i++)//枚举第一项
    {
        for(j = i + 1; j < arrSize; j++)//枚举第二项
        {
            int conut = dfs(arr, arrSize, i, j, (int **)res);//以第一项第二项开始的斐波那契序列长度
            if(conut >= 3)
            {
                max = MAX(max , conut);//保存最大值
            }
        }
    }
    for(i = 0; i < arrSize; i++)//释放空间
    {
        free(res[i]);
    }
    free(res);
    return max;
}

时间空间复杂度

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值