最长公共子序列(LCS)

朴灿烈づ我的快乐病毒、 2022-10-14 13:54 270阅读 0赞

最长公共子序列(LCS)

problem

leetcode: 1035. 不相交的线

dp[i][j]:nums1[0:i] 和nums2[0:j]的LCS;
如果nums1[i]==nums2[j],则: dp[i][j] = dp[i-1][j-1] + 1,
否则: dp[i][j] = max(dp[i-1][j],dp[i][j-1]).
为了不额外处理边界,记录ans的dp数组整体后移动一位。

code

  1. class Solution {
  2. public:
  3. int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
  4. int m = nums1.size();
  5. int n = nums2.size();
  6. vector<vector<int>>dp(m+1,vector<int>(n+1,0));
  7. // 两个序列的LCS
  8. for(int i = 1; i <= m; ++i)
  9. {
  10. for(int j = 1; j <= n; ++j)
  11. {
  12. if(nums1[i-1] == nums2[j-1])
  13. {
  14. dp[i][j] = dp[i-1][j-1] + 1;
  15. }
  16. else
  17. {
  18. dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
  19. }
  20. }
  21. }
  22. return dp[m][n];
  23. }
  24. };

为了看看有没有优化版本,去洛谷找了一个LCS题目做,遇到一个有意思的题目:洛谷:P1439 【模板】最长公共子序列

n高达1e5,这个题直接用 O ( n 2 ) O(n^2) O(n2)的 LCS是过不了的。

再认真读题,两个序列是1-n的排列

样例:

  1. 5
  2. 3 2 1 4 5
  3. 1 2 3 4 5

如果第一个序列映射成它的index,即:

  1. 3:0, 2:1, 1:2, 4:3, 5:4

则第二个序列根据第一个序列的映射关系,被映射成了:

  1. 2 1 0 3 4

两个序列经过映射后变成:

  1. 0 1 2 3 4
  2. 2 1 0 3 4

我们可以发现映射后第一个序列一定是严格升序的,

此时只需要找映射后第二个子序列的最长上升子序列(LIS)

LIS的长度就是原来两个由1-n排列构成的序列的LCS。

很神奇的将LCS转化成了LIS。

可以使用基于贪心的 O ( N l o g N ) O(NlogN) O(NlogN)解法求解LIS。

code

非c++11 请将unordered_map换成map

  1. #include <iostream>
  2. #include <vector>
  3. #include <unordered_map>
  4. using namespace std;
  5. const int INF = 0x3f3f3f3f;
  6. int main()
  7. {
  8. int n;
  9. cin>>n;
  10. vector<int>A(n);
  11. vector<int>B(n);
  12. unordered_map<int,int>mp,num;
  13. for(int i = 0; i < n; ++i)
  14. {
  15. cin>>A[i];
  16. mp[A[i]] = i;
  17. }
  18. for(int j = 0; j < n; ++j)
  19. {
  20. cin>>B[j];
  21. num[j] = mp[B[j]];
  22. }
  23. vector<int>st(n+5);
  24. int k = 0;
  25. st[0] = -INF;
  26. // O(nlogn) LIS
  27. for(int i = 0; i < n; ++i)
  28. {
  29. if(num[i]>st[k])
  30. {
  31. st[++k] = num[i];
  32. }
  33. else
  34. {
  35. int l = 1;
  36. int r = k;
  37. int pos = -1;
  38. while(l <= r)
  39. {
  40. int mid = l + (r-l)/2;
  41. if(st[mid]>num[i])
  42. {
  43. pos = mid;
  44. r = mid - 1;
  45. }
  46. else
  47. {
  48. l = mid + 1;
  49. }
  50. }
  51. if(pos != -1) st[pos] = num[i];
  52. }
  53. }
  54. cout<<k<<endl;
  55. return 0;
  56. }

发表评论

表情:
评论列表 (有 0 条评论,270人围观)

还没有评论,来说两句吧...

相关阅读

    相关 公共序列LCS问题

    好久没有写博客了,刚才在网上看了清华大学的数据结构公开课,链接:https://www.xuetangx.com 可以注册个账号去听数据结构课程,老师讲的特好。 我的代码是按

    相关 LCS 公共序列

    首先要明白什么是子序列,什么是子串; 设:主串长度为n; 子序列:从主串中抽出少于n的元素组成的序列(这些抽出的元素比一定是连续的他们的相对位置不变);