思路:动态规划。
其实这道题和最长递增子序列很像,都是以数字为结尾的dp形式,也就是把判断条件改了一下就是了。
这里首先我们用二重循环来做一下,发现会时间超时,因为这里的时间数是大于10万的,所以要么就是O(n),我们需要对dp进行优化操作才行。
为什么要+1,因为自身也算是一个数,我们在dp递推的时候并没有考虑自身的问题,所以你可以在初始化dp的时候进行初始化为1,也可以最后把数加上1。
首先上二重循环的DP:
class Solution {
public:int longestSubsequence(vector<int>& arr, int difference) {int n=arr.size();vector<int>dp(100100,0);int res=0;for(int i=0;i<n;i++){for(int j=0;j<i;j++){if(arr[i]-arr[j]==difference){dp[i]=max(dp[i],dp[j]+1);}}res=max(dp[i],res);}return res+1;}
};
接下来就是基于对于二重循环的优化了:
我们从最长递增子序列的思路中可以知道,dp[i]的数组判断的是以arr[i]为尾的最长定差子序列,我们的dp下标其实对应的就是arr[i]在arr数组中的位置。换个思路想,如果我们直接把arr[i]代表的数放dp的下标会如何呢?
假设arr[i]的数表示为v,那么dp[v]也就表示了以v为结尾的最长定差子序列的长度了。那么,状态转移方程又怎么变化呢?由于我们总是在以这个数字为尾,况且我们寻找的是它左边的数,所以只需要在本数的基础上减去定差就行了,也就是对于数组左边的探测了。如果有,自然就会+1,另外会带着这个数字为尾的最长定差子序列,就这样一直递推下去。
上代码:
class Solution {
public:int longestSubsequence(vector<int>& arr, int difference) {int n=arr.size();unordered_map<int,int>dp;int res=0;for(int i=0;i<n;i++){dp[arr[i]]=dp[arr[i]-difference]+1;res=max(res,dp[arr[i]]);}return res;}
};