LeetCode-1218 [最长定差子序列]
LeetCode-1218 最长定差子序列
- 题目
给你一个整数数组 arr 和一个整数 difference,请你找出并返回 arr 中最长等差子序列的长度,该子序列中相邻元素之间的差等于 difference 。
子序列 是指在不改变其余元素顺序的情况下,通过删除一些元素或不删除任何元素而从 arr 派生出来的序列。
-
思路
-
暴力搜索
数组为arr,为了找到数组中的最长等差数列,可以遍历数组中的每一个值,最后对整个结果数组求max即可,如何求以该点为结尾的最长等差数列,以该点
arr[i]
为起始,反向遍历,查找arr[i]-differance
是否存在,如果不存在,意味着不存在以该点位结尾的等差数列,直接置为1,如果存在一个arr[j]
,使得arr[j]+differance=arr[i](j<i)
,那么res[i]=res[j]+1
,优化:
对于每个数字,都要反向遍历查找
arr[i]-differance
,我们可以使用map直接存储当前位置之前所有出现的数组中最长的等差子序列,eg:
1 2 5 7 differance=3
遍历到5时,map中为【
map[1]=1,map[2]=1
】,此时直接判断map[5-3]
是否等于0,不等于0代表有存在diferance的等差数列,此时等差数组长度增长1。map[5]=map[5-3]+1
-
动态规划
使用
dp[arr[i]]
存储以该点为结尾的最长等差序列的长度通过上述得知:
\[dp[arr[i]]=dp[arr[i]-differance]+1 \]从左往右遍历,结果为$$max(dp)$$
-
-
Code
- 暴力搜索(超时)
class Solution { public: int longestSubsequence(vector<int>& arr, int difference) { vector<int> dp(arr.size()); dp[0]=1; int max=1; for(int i=1;i<arr.size();i++){ int j; for(j=i-1;j>=0;j--){ if(arr[j]+difference==arr[i]){ break; } } if(j>=0){ dp[i]=dp[j]+1; if(dp[i]>max){ max=dp[i]; } } else{ dp[i]=1; } } return max; } };
- 优化
class Solution { public: int longestSubsequence(vector<int>& arr, int difference) { vector<int> dp(arr.size()); map<int,int> max_v; dp[0]=1; int max=1; max_v[arr[0]]=1; for(int i=1;i<arr.size();i++){ int search=arr[i]-difference; if(max_v[search]!=0){ dp[i]=max_v[search]+1; if(dp[i]>max){ max=dp[i]; } max_v[arr[i]]=dp[i]; } else{ dp[i]=1; max_v[arr[i]]=dp[i]; } } return max; } };
- 动态规划
class Solution { public: int longestSubsequence(vector<int>& arr, int difference) { unordered_map<int,int> dp; dp[arr[0]]=1; int res=1; for(int i=1;i<arr.size();i++){ dp[arr[i]]=dp[arr[i]-difference]+1; res=max(dp[arr[i]],res); } return res; } };