当前位置:网站首页>线性dp求解 最长子序列 —— 小题三则
线性dp求解 最长子序列 —— 小题三则
2022-07-02 10:28:00 【小酒窝.】
目录
一、最长连续等差数列
题意
给定一个包含 N N N 个非负整数的数组,其中的第 i i i 个整数为 A i A_i Ai。
求最长连续等差数列长度。
1 ≤ T ≤ 100 , 1 ≤ A i ≤ 1 0 9 1≤T≤100,1≤A_i≤10^9 1≤T≤100,1≤Ai≤109
思路1:dp,O(n)
既然是连续的,那只能从前一个位置转移,判断当前值 a[i] 和上一位置 a[i-1] 的差值是否能和上上位置 a[i-2] 构成等差数列。如果能,就从上一位置的状态转移。
状态定义:f[i] 表示以 i 位置结尾的最长连续等差数列长度。
状态转移:
if(a[i] - a[i-1] == a[i-1] - a[j-2]) f[i] = f[i-1] + 1;
else f[i] = 1;
Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], f[N];
signed main(){
scanf("%d", &T);
for(int cs = 1; cs <= T; cs ++)
{
scanf("%d", &n);
for(int i=1;i<=n;i++) scanf("%d", &a[i]), f[i] = 1;
int ans = 1;
f[1] = 0;
for(int i=2;i<=n;i++)
{
if(a[i]-a[i-1] == a[i-1]-a[i-2]) f[i] = f[i-1]+1;
ans = max(ans, f[i]);
}
if(n == 1) ans = 0;
printf("Case #%d: %d\n", cs, ans+1);
}
return 0;
}
思路2:差分,O(n)
等差数列性质,差值为定值,也就是说等差数列的差分数组中的所有值都相同。
所以维护差分求最长相同子串就行了。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], f[N];
signed main(){
scanf("%d", &T);
for(int cs = 1; cs <= T; cs ++)
{
scanf("%d", &n);
for(int i=1;i<=n;i++) scanf("%d", &a[i]);
for(int i=1;i<=n;i++) f[i] = a[i] - a[i-1];
f[0] = 1e9+1; //特判第0个位置,将后面的+1用于所有情况。防止出现1 2这样的情况。
int ans = 0;
for(int i=1;i<=n;i++)
{
int j = i+1;
while(f[j] == f[i] && j<=n) j++;
ans = max(ans, j-i);
i = j-1;
}
if(n == 1) ans = 0;
printf("Case #%d: %d\n", cs, ans+1);
}
return 0;
}
二、最长等差子序列
题意
给定一个包含 N N N 个非负整数的数组,其中的第 i i i 个整数为 A i A_i Ai。
求最长等差子序列的长度。(子序列在原数组中不一定连续)
1 ≤ T ≤ 100 , 1 ≤ A i ≤ 1 0 9 1≤T≤100,1≤A_i≤10^9 1≤T≤100,1≤Ai≤109
思路1:dp,O(nm),m 为 Ai 最大值
状态定义:
定义 f[i, j, k] 表示,以值 i 作为等差数列末位置,差值绝对值为 j,差值正负为 k 时,最长等差子序列长度。(k ∈ {0, 1})
状态转移:
用前面位置所更新的 f[] 来更新当前位置。
f[nums[i]][j][0] = f[nums[i]+j][j][0] + 1;
if(nums[i]>=j) f[nums[i]][j][1] = f[nums[i]-j][j][1] + 1;
else f[nums[i]][j][1] = 1;
Code:
class Solution {
/* 需要特别注意的是,如果a[i]+j没有出现过,那么其可以用f[a[i]+j][j]来更新为1;但是如果a[i]-j没有出现过,并且为负数的话,这个f[a[i]-j]就不会更新为1,仍然为0,就会出现错误。所以这种情况要特判为1。 另外也不能用max(0, a[i]-j)来更新,因为在这道题中f[0]是有值的,不是始终为0。 */
public:
int longestArithSeqLength(vector<int>& nums) {
int f[1010][510][2]{
};
int ans = 0;
for(int i=0;i<nums.size();i++)
{
for(int j=0;j<=500;j++)
{
f[nums[i]][j][0] = f[nums[i]+j][j][0] + 1;
if(nums[i]>=j) f[nums[i]][j][1] = f[nums[i]-j][j][1] + 1;
else f[nums[i]][j][1] = 1;
ans = max(ans, f[nums[i]][j][0]); ans = max(ans, f[nums[i]][j][1]);
}
}
return ans;
}
};
思路2:dp,O(n^2)
一种等差数列至少需要两个相邻位置来确定,所以可以定义两维状态来表示以这两个位置为末位置的等差数列最长长度。
状态定义:
定义 f[i, j] 表示,以 i, j 这两个位置作为末位置的等差序列的最长长度。
状态转移:f[i][j] = f[mp[2*a[i]-a[j]]][i] + 1,mp[x] 用以得到值 x 在前面出现的位置。
更新时,对于当前位置 i,遍历其后面所有位置 j,通过这两个值算出最前面的位置 k。用前面的 f[k, i] 来更新后面的 f[i, j]。
这里还用到一个技巧,由当前值和后面枚举的值可以算出等差数列前面一个位置的值,但是如何找到该值在数组中的位置呢?
可以直接用 map 标记,标记该值最后一次出现的位置。
(最后一次,那前面位置不能更新么?也是可以的,只是后面位置所能更新的长度一定不会小于前面位置所能更新长度,所以直接用最后一次出现位置来更新即可)
把当前位置 i 遍历之后,再把 a[i] 出现的位置标记为 i,这样便能保证 mp[x] 出现的位置一定在当前位置之前,用前面的答案来更新后面。
Code:
class Solution {
public:
int longestArithSeqLength(vector<int>& a) {
unordered_map<int,int> mp;
int f[1010][1010]{
};
int ans = 0;
for(int i=0;i<a.size();i++){
for(int j=i+1;j<a.size();j++)
{
if(!mp.count(2*a[i]-a[j])) continue;
f[i][j] = f[mp[2*a[i]-a[j]]][i] + 1;
ans = max(ans, f[i][j]);
}
mp[a[i]] = i;
}
return ans + 2;
}
};
三、最长斐波那契子序列
题意
给定一个包含 N N N 个正整数的严格递增数组,其中的第 i i i 个整数为 A i A_i Ai。
求最长斐波那契子序列的长度。(子序列在原数组中不一定连续)
如果序列 X 1 , X 2 , . . . , X n X_1, X_2, ..., X_n X1,X2,...,Xn 满足下列条件,就说它是 斐波那契式 的:
- n >= 3
- 对于所有 i + 2 <= n,都有 X i + X i + 1 = X i + 2 X_i + X_{i+1} = X_{i+2} Xi+Xi+1=Xi+2
思路1:set暴力,O( n 2 l o g m n^2logm n2logm),m为 Ai 最大值
将整个数组存到 set 里,二重循环遍历数列前两个位置,对于每两个初始位置,得出接下来一个数的位置。set判断其是否存在,存在的话长度++,位置更新,不断往后走。
因为是严格递增的,并且数列以斐波那契式增长,最长有43项,所以整体复杂度为O( n 2 l o g m n^2logm n2logm)。
(正因为是单调递增的,非常巧妙的用set来搞)
Code
class Solution {
public:
int lenLongestFibSubseq(vector<int>& v) {
set<int> st(v.begin(), v.end());
int ans = 0;
for(int i=0;i<v.size();i++)
for(int j=i+1;j<v.size();j++)
{
int x = v[i], y = v[j];
int len = 2;
while(st.find(x+y) != st.end())
{
int z = x + y;
x = y;
y = z;
len ++;
}
ans = max(ans, len);
}
return ans > 2 ? ans : 0;
}
};
思路2:dp,O(n^2)
思路和上一题的第二种解法相同。
状态定义:
定义 f[i, j] 表示,以 i, j 位置作为末位置的斐波那契子序列的最长长度。
状态转移:f[i][j] = f[mp[2*a[i]-a[j]]][i] + 1,其中 mp[x] 表示值 x 在当前位置 i 前面出现的位置。
对于当前位置 i 作为数列第2项,遍历后面的所有位置 j 作为数列第3项,通过这两个位置的值计算出第1项的值,mp[x] 得到其位置 k。
由位置 k 和 i 确定的数列来更新由位置 i 和 j 确定的数列。
同样,为了保证 mp[x] 是在当前位置 i 之前的,在遍历过当前位置之后再将 i 位置加到 map 中。
Code
class Solution {
public:
int lenLongestFibSubseq(vector<int>& a) {
unordered_map<int, int> mp;
int f[1010][1010]{
};
int ans = 0;
for(int i=0;i<a.size();i++){
for(int j=i+1;j<a.size();j++)
{
if(!mp.count(a[j]-a[i])) continue;
f[i][j] = max(f[i][j], f[mp[a[j]-a[i]]][i] + 1);
ans = max(ans, f[i][j]);
}
mp[a[i]] = i;
}
ans += 2;
return ans > 2 ? ans : 0;
}
};
由此可以看出,思路2对于求解这样的子序列问题具有普适性,应该熟练记忆。
边栏推荐
- Student course selection information management system based on ssm+jsp framework [source code + database]
- (POJ - 1984) navigation nightare (weighted and search set)
- Don't spend money, spend an hour to build your own blog website
- Subcontracting configuration of uniapp applet subpackages
- selenium 元素定位方法
- ArrayList and LinkedList
- Selenium installing selenium in pycharm
- What are eNB, EPC and PGW?
- Memory management 01 - link script
- 你知道Oracle的数据文件大小有上限么?
猜你喜欢

Design of non main lamp: how to make intelligent lighting more "intelligent"?

为什么switch 的default后面要跟break?

瀏覽器驅動的下載

Why is the default of switch followed by break?

Selenium installing selenium in pycharm

Use of UIC in QT

代码实现MNLM
![Student course selection information management system based on ssm+jsp framework [source code + database]](/img/71/900d83dba41974589b15d23e632119.png)
Student course selection information management system based on ssm+jsp framework [source code + database]

ensp简单入门

Origin plots thermogravimetric TG and differential thermogravimetric DTG curves
随机推荐
Tupang multi-target tracking! BOT sort: robust correlated multi pedestrian tracking
Don't spend money, spend an hour to build your own blog website
P1908 逆序对
Qt入门-制作一个简易的计算器
Code implementation MNLM
selenium 元素定位方法
Which do you choose between Alibaba P7 with an annual salary of 900000 and deputy department level cadres?
P1042 [noip2003 popularization group] Table Tennis
Error function ERF
(POJ - 1984) navigation nightare (weighted and search set)
QT - make a simple calculator - realize four operations
Whole house Wi Fi: a pain point that no one can solve?
Winter vacation daily question - lucky numbers in the matrix
【模板】最长公共子序列 (【DP or 贪心】板子)
【文档树、设置】字体变小
Three talking about exception -- error handling
P1347 sorting (topology + SPFA judgment ring or topology [inner judgment ring])
The global special paper revenue in 2021 was about $27 million, and it is expected to reach $35 million in 2028. From 2022 to 2028, the CAGR was 3.8%
D为何链接不了dll
Qt原代码基本知识