等差子段的个数
int numberOfArithmeticSlices(vector<int>& A) {
// 设dp[i]表示以A[i]结尾的等差子段数。
// 若A[i]-A[i-1]=A[i-1]-A[i-2]时,dp[i]=dp[i-1]+1;
// 其中dp[i-1]来自扩展的旧子段,1来自新出现的长度==3的子段。
// 若不满足等差,dp[i]=0。
// 初始dp[0]=dp[1]=0,因为长度要>=3。
// i这维只依赖前一项,省掉i这维,满足等差时dp+=1,不满足时dp=0。
int dp = 0, ans = 0;
for (int i = 2; i < A.size(); i++) {
if (A[i] - A[i-1] == A[i-1] - A[i-2]) {
dp += 1;
ans += dp;
} else {
dp = 0;
}
}
return ans;
}
等差子序列的个数
设dp[i]表示以A[i]结尾的等差子序列个数,递推过程太复杂,说明假设缺少信息。
int numberOfArithmeticSlices(vector<int>& A) {
// 设dp[i][d]表示以A[i]结尾、等差为d、长度>=2的等差子序列数。
// 对所有j<i,d=A[i]-A[j],dp[i][d]=sum(dp[j][d]+1)
// 其中dp[j][d]来自扩展的旧序列,1来自新出现的长度==2序列
// 优化:由于d是两数之差,范围无限,dp[i][d]的d这一维要用unordered_map
// 要用dp[j].count(d)测试,防止d值不存在时往map里添0,导致内存溢出
const int N = A.size();
vector<unordered_map<int,int>> dp(N);
int ans = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < i; j++) {
long d = (long)A[i] - A[j];
if (d < INT_MIN || d > INT_MAX) continue; // pass OL
int dp_jd = dp[j].count(d) ? dp[j][d] : 0;
dp[i][d] += dp_jd + 1;
// dp[j][d]是扩展的旧序列,现在长度>=3,统计长度>=3的
ans += dp_jd;
}
}
return ans;
}
最长等差子序列
int longestArithSeqLength(vector<int>& A) {
// 最长等差子序列长
// 设dp[i][d]表示以A[i]结尾、等差为d的子问题解
const int N = A.size();
vector<unordered_map<int,int>> dp(N);
int ans = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < i; j++) {
int d = A[i] - A[j];
dp[i][d] = dp[j].count(d) ? (dp[j][d] + 1) : 2;
ans = max(ans, dp[i][d]);
}
}
return ans;
}
指定等差的最长子序列
int longestSubsequence(vector<int>& arr, int difference) {
// 最长指定差的子序列长
// ~~O(n^2)解法超时:设dp[i]表示以A[i]结尾、等差为difference的子问题解~~
// 设dp[v]表示子序列结尾值为v的子问题解,dp[v] = dp[v-difference]+1
unordered_map<int, int> dp; // 子序列结尾值v=>子序列长
int ans = 0;
for (int v : arr) {
dp[v] = dp.count(v - difference) ? dp[v - difference] + 1 : 1;
ans = max(ans, dp[v]);
}
return ans;
}
最长Fib子序列
int lenLongestFibSubseq(vector<int>& A) {
// 设dp[i][j]表示以A[i]、A[j]结尾的长>=2的最长Fib子序列长
// 将A中值作val=>idx的映射,i,j的前一个索引idx=mp[A[j]-A[i]],
// dp[i][j] = dp[idx][i] + 1
// i从左往右遍历,j从左往右遍历
const int N = A.size();
unordered_map<int, int> mp; // val=>idx
vector<vector<int>> dp(N, vector<int>(N, 0));
int ans = 0;
for (int j = 0; j < N; j++) {
mp[A[j]] = j;
for (int i = 0; i < j; i++) {
int val = A[j] - A[i];
if (val < A[i] && mp.count(val)) {
int idx = mp[val];
dp[i][j] = dp[idx][i] + 1; // dp[i][j]现在>=3
ans = max(ans, dp[i][j]);
} else {
dp[i][j] = 2;
}
}
}
return ans;
}