Given an array A
of integers, return the length of the longest arithmetic subsequence in A
.
Recall that a subsequence of A
is a list A[i_1], A[i_2], ..., A[i_k]
with 0 <= i_1 < i_2 < ... < i_k <= A.length - 1
, and that a sequence B
is arithmetic if B[i+1] - B[i]
are all the same value (for 0 <= i < B.length - 1
).
Example 1:
Input: A = [3,6,9,12]
Output: 4
Explanation:
The whole array is an arithmetic sequence with steps of length = 3.
Example 2:
Input: A = [9,4,7,2,10]
Output: 3
Explanation:
The longest arithmetic subsequence is [4,7,10].
Example 3:
Input: A = [20,1,15,3,10,5,8]
Output: 4
Explanation:
The longest arithmetic subsequence is [20,15,10,5].
Constraints:
2 <= A.length <= 1000
0 <= A[i] <= 500
這道題給了一個數組,讓找最長的等差數列的長度,暴力搜索的時間復雜度太大,這里就不考慮了。像這種玩數組,求極值的題,刷題老司機們應該很容易就反應出應該用動態規划 Dynamic Programming 來做,首先來考慮如何定義 DP 數組,最直接的就是用一個一維數組,其中 dp[i] 表示區間 [0, i] 中的最長等差數列的長度,但是這樣定義的話,很難找出狀態轉移方程。因為有些隱藏信息被我們忽略了,就是等差數列的相等的差值,不同的等差數列的差值可以是不同的,所以不包括這個信息的話將很難更新 dp 值。所以這里就需要一個二維數組,dp[i][j] 表示在區間 [0, i] 中的差值為j的最長等差數列的長度減1,這里減1是因為起始的數字並沒有被算進去,不過不要緊,最后再加回來就行了。還有一個需要注意的地方,由於等差數列的差值有可能是負數,而數組的下標不能是負數,所以需要處理一下,題目中限定了數組中的數字范圍為0到 500 之間,所以差值的范圍就是 -500 到 500 之間,可以給差值加上個 1000,這樣差值范圍就是 500 到 1500 了,二維 dp 數組的大小可以初始化為 nx2000
。更新 dp 值的時候,先遍歷一遍數組,對於每個遍歷到的數字,再遍歷一遍前面的所有數字,算出差值 diff,再加上 1000,然后此時的 dp[i][diff] 可以賦值為 dp[j][diff]+1,然后用這個新的 dp 值來更新結果 res,最后別忘了 res 加1后返回,參見代碼如下:
class Solution {
public:
int longestArithSeqLength(vector<int>& A) {
int res = 0, n = A.size();
vector<vector<int>> dp(n, vector<int>(2000));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
int diff = A[i] - A[j] + 1000;
dp[i][diff] = dp[j][diff] + 1;
res = max(res, dp[i][diff]);
}
}
return res + 1;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1027
參考資料:
https://leetcode.com/problems/longest-arithmetic-subsequence/
https://leetcode.com/problems/longest-arithmetic-subsequence/discuss/274611/JavaC%2B%2BPython-DP