【區間 dp】B024_LC_最長等差數列(unordered_map + dp)

一、Problem

給定一個整數數組 A,返回 A 中最長等差子序列的長度。

回想一下,A 的子序列是列表 A[i_1], A[i_2], …, A[i_k] 其中 0 <= i_1 < i_2 < … < i_k <= A.length - 1。並且如果 B[i+1] - B[i]( 0 <= i < B.length - 1) 的值都相同,那麼序列 B 是等差的。

輸入:[20,1,15,3,10,5,8]
輸出:4
解釋:
最長的等差子序列是 [20,15,10,5]。

提示:

2 <= A.length <= 2000
0 <= A[i] <= 10000

二、Solution

方法一:dp

  • 定義狀態
    • f[i][d]f[i][d] 表示數組區間 [0,i][0, i] 中,公差爲 d 的最長等差數列長度
  • 思考初始化:
    • f[0:][0:]=0f[0:][0:] = 0
  • 思考狀態轉移方程
    • 如果 A[i]A[j]=df[j][d]!=0A[i] - A[j] = d,f[j][d] != 0,則有 f[i][d]=f[j][d]+1f[i][d] = f[j][d] + 1
    • 否則,f[i][d]=2f[i][d] = 2
  • 思考輸出max(f[0:][0:])max(f[0:][0:])

ps:這裏我直接用 C++ 寫的,C++ 有運算符重載真的很方便,大愛 C++,如果不用 map,那麼就要根據數據範圍將公差爲負數的情況轉爲正數,再做狀態轉移

class Solution {
public:
    int longestArithSeqLength(vector<int>& A) {
    	int n = A.size(), ans = 1;
    	vector<unordered_map<int,int>> f(n); 
        
    	for (int i = 1; i < n; i++)
		for (int j = 0; j < i; j++) {
			int d = A[i] - A[j];
			if (f[j][d]) f[i][d] = f[j][d] + 1;
			else 		 f[i][d] = 2;
			ans = max(ans, f[i][d]);
		}
		return ans;
    }
};

複雜度分析

  • 時間複雜度:O(n2)O(n^2)
  • 空間複雜度:O(n)O(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章