【動態規劃】最長斐波那契數列和最長等差數列
阿新 • • 發佈:2022-03-05
今天總結一下Leetcode上的兩道看可以用同一解法實則不可生搬硬套的兩道相似題。
1、873. 最長的斐波那契子序列的長度 - 力扣(LeetCode) (leetcode-cn.com)
本題的難點在於狀態定義:與一般的dp題不同,這裡我們選擇將dp陣列定義為:dp[i][j]表示以arr[i],arr[j]結尾的斐波那契數列的最大長度。因為想要確定一個斐波那契數列需要三個值arr[i],arr[j],arr[k],如果直接定義首先會出現一個三重迴圈,並且許多細節難以言表。。。將狀態轉移陣列定義成上述表示可以根據性質:arr[k]+arr[i]=arr[j]來確定k的值,減小迴圈數。為了獲取下標需要一個hash表來將各個元素的下標提取出來(由於陣列嚴格遞增,所以我們不用擔心重複問題)。k由Index[arr[i]-arr[j]]唯一確定。
class Solution { public: int lenLongestFibSubseq(vector<int>& arr) { int n=arr.size(); unordered_map<int,int> Index; for(int i=0;i<n;i++){ Index[arr[i]]=i; } int res=0; unordered_map<int,int> longest; for(int i=0;i<n;i++){ for(int k=0;k<i;k++){ if(Index.count(arr[i]-arr[k])&&arr[i]-arr[k]<arr[k]){ int j=Index[arr[i]-arr[k]]; longest[k*n+i]=longest[j*n+k]+1; res=max(res,longest[k*n+i]+2); } } } return res>=3?res:0; } };
時間複雜度:O(n2)
2、1027. 最長等差數列 - 力扣(LeetCode) (leetcode-cn.com)
這道題與上一道題十分相似,像我這樣的新手很容易慣性思維直接套用上題的解法。但其實在這裡是有問題的。因為題目中給定的陣列nums並沒有說明是嚴格遞增的,這意味著陣列中可能會出現重複元素,從而在確定第三維的下標時產生重複。因此在這裡我們將狀態定義為:dp[i][j]表示以nums[i]結尾的公差為j的等差數列的最大長度。根據題目所給的資料範圍:0<=nums[i]<=500我們可以確定公差的範圍-500<=d<=500,因此我們將公差加上500使之恆正,便於我們定義dp陣列。根據nums[i]-nums[j]+500來唯一確定公差。其他的便與LIS演算法相似。
class Solution {
public:
int longestArithSeqLength(vector<int>& nums) {
int n=nums.size();
vector<vector<int>> dp(n,vector<int>(1001,0));
int res=0;
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
int d=nums[i]-nums[j]+500;
dp[i][d]=max(dp[i][d],dp[j][d]+1);
res=max(res,dp[i][d]);
}
}
return res+1;
}
};