LIS、LCS

博客介绍了LIS(Longest Increasing Subsequence)和LCS(Longest Common Subsequence)的相关解法。对于LIS,有朴素三角dp和NlgN解法,也可排序+LCS;对于LCS,有朴素矩形dp、滚动数组dp和NlgN解法,滚动数组需先写矩形再优化,NlgN在重复元素多时有局限。

LIS:Longest Increasing Subsequence

  • 朴素三角dp,注意初始化为1:
int ans = 0;
for(int i=0;i<N;i++){
	dp[i] = 1;//important
	for(int j=0;j<i;j++)
		if(A[i] > A[j])
			dp[i] = max(dp[i] , dp[j] + 1);
	ans = max(ans , dp[i]);
}
  • NlgN:
memset(dp , INF , sizeof(dp));
for(int i=0;i<N;i++)
	*lower_bound(dp , dp+N , A[i]) = A[i];
cout<<lower_bound(dp , dp+N , INF) - dp<<endl;
  • 也可以排序+LCS,但是没有必要。

LCS:Longest Common Subsequence

  • 朴素矩形dp,注意向后腾出一枚空间:
memset(dp , 0 , sizeof(dp))for(int i=0;i<l.length();i++)
	for(int j=0;j<r.length();j++)
		if(l[i] == r[j])
			dp[i+1][j+1] = dp[i][j] + 1;
		else
			dp[i+1][j+1] = max(dp[i+1][j] , dp[i][j+1]);
cout<<dp[l.length()][r.length()]<<endl;
  • 滚动数组dp:注意为什么需要留下两维:必须先写矩形,再根据矩形优化到滚动数组
memset(dp , 0 , sizeof(dp));
int t = 0 ;
for(int i=0;i<l.length();i++){
	t = 1 - t;
	for(int j=0;j<r.length();j++)
		if(l[i] == r[j])
			dp[t][j+1] = dp[1-t][j] + 1;
		else
			dp[t][j+1] = max(dp[t][j] , dp[1-t][j+1]); 
}
cout<<dp[l.length()%2][r.length()]<<endl;
  • NlgN:记录位置,再NlgN做LIS,但是在重复元素较多时,一般并不能真正起到效果
int cnt = 0;
for(int i=0;i<l.length();i++)
	for(int j=r.length();j>=0;j--)
		if(l[i] == r[j])
			F[++cnt] = j;
memset(dp , INF , sizeof(dp));
for(int i=1;i<=cnt;i++) 
	*lower_bound(dp , dp+cnt , F[i]) = F[i];
cout<<lower_bound(dp , dp+cnt , INF) - dp<<endl;
### C++ 中实现 LISLCS 的解决方案 #### 最长递增子序列 (LIS) 对于最长递增子序列问题,在C++中的一个高效解法利用了二分查找来优化时间复杂度至 O(n log n)[^3]。下面展示了一个具体的实现方式: ```cpp #include <vector> #include <algorithm> using namespace std; int lengthOfLIS(vector<int>& nums) { vector<int> temp; for(int num : nums){ auto it = lower_bound(temp.begin(), temp.end(), num); if(it == temp.end()) temp.push_back(num); else *it = num; } return temp.size(); } ``` 此代码片段通过维护一个临时数组 `temp` 来追踪当前找到的递增子序列,当遍历到新元素时,如果该元素大于 `temp` 数组中所有元素,则将其追加到后面;否则替换掉第一个比它大的数。 #### 最长公共子序列 (LCS) 针对两个给定字符串之间的最长公共子序列计算,可以采用动态规划的方法来进行处理[^1]。以下是使用C++编写的函数用于返回两输入字符串 s1 和 s2 的 LCS 长度: ```cpp #include <string> #include <vector> using namespace std; int longestCommonSubsequence(string text1, string text2) { int m = text1.length(), n = text2.length(); vector<vector<int>> dp(m + 1, vector<int>(n + 1)); for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (text1[i - 1] == text2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } return dp[m][n]; } ``` 上述程序创建了一个二维表 `dp[][]` ,其中每一项代表截至当前位置所能获得的最大匹配字符数量。最终结果保存于表格右下角位置即为所求得的最长公共子序列长度。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值