力扣
题目
示例
思路
求斐波那契数列
我们可以枚举斐波那契数列的前两项,然后判断数组中是否有第三项即可。但是这样子时间开销非常大,会超时,所以我们用空间换时间法
在上面方法中我们可能会重复计算某些元素,如计算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;
}
时间空间复杂度