Given an integer array arr
and an integer difference
, return the length of the longest subsequence in arr
which is an arithmetic sequence such that the difference between adjacent elements in the subsequence equals difference
.
A subsequence is a sequence that can be derived from arr
by deleting some or no elements without changing the order of the remaining elements.
Example 1:
Input: arr = [1,2,3,4], difference = 1
Output: 4
Explanation: The longest arithmetic subsequence is [1,2,3,4].
Example 2:
Input: arr = [1,3,5,7], difference = 1
Output: 1
Explanation: The longest arithmetic subsequence is any single element.
Example 3:
Input: arr = [1,5,7,8,5,3,4,2,1], difference = -2
Output: 4
Explanation: The longest arithmetic subsequence is [7,5,3,1].
Constraints:
1 <= arr.length <= 105
-104 <= arr[i], difference <= 104
這道題讓求給定差值的最長等差子序列,既然是子序列,就表示數字是不用連續的。對於這種數組玩極值的題目,很大的可能就是用動態規划 Dynamic Programming 來做,這道題也不例外。博主最開始想的方法比較簡單粗暴,用一個一維的 DP 數組,其中 dp[i] 表示最后一個數字是 arr[i] 的等差子序列的長度,對於狀態轉移方程就是遍歷每個 [0, i-1] 區間的j,若 dp[i] - dp[j] 等於 difference,則用 dp[j]+1 來更新 dp[i],但是這種平方級時間復雜度的方法還是不幸超時了 Time Limit Exceeded,對於一道 Medium 的題目,卡的這么嚴是博主沒有想到的。
那怎么辦呢,還有什么更快的方法嗎?有的,這里博主先賣個關子,首先來思考一下,為啥上面的解法會超時,因為每次都遍歷 arr[i] 前面所有的數字,絕大部分的遍歷操作都是無效的,因為差值不是給定的 difference。這里既然差值是確定的,直接通過 arr[i] - difference 就是前一個數字了,只需要快速知道這個數字是否存在,而且最好還能知道以這個數字結尾的等差子序列的長度。這樣的話,用 HashMap 建立一個映射就比較方便了,於是乎 dp[i] 就表示以數字i結尾的等差子序列的長度,更新的時候也很方便,用 1 + dp[i-difference] 來更新 dp[i],然后用 dp[i] 來更新結果 res 即可,參見代碼如下:
class Solution {
public:
int longestSubsequence(vector<int>& arr, int difference) {
int res = 0;
unordered_map<int, int> dp;
for (int i : arr) {
dp[i] = 1 + dp[i - difference];
res = max(dp[i], res);
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1218
參考資料:
https://leetcode.com/problems/longest-arithmetic-subsequence-of-given-difference/