题解 | #最长公共子序列(二)#
最长公共子序列(二)
https://www.nowcoder.com/practice/6d29638c85bb4ffd80c020fe244baf11
#include <unordered_map> #include <vector> class Solution { public: /** * longest common subsequence * @param s1 string字符串 the string * @param s2 string字符串 the string * @return string字符串 */ string LCS(string s1, string s2) { // write code here unordered_map<char, vector<int>> hash_map; unordered_map<int, char> reverse_map; vector<int> map_arr; for(int i=0;i<s1.size();i++){ vector<int> tmp; if(hash_map.find(s1[i])!=hash_map.end()) tmp = hash_map[s1[i]]; tmp.push_back(i); hash_map[s1[i]] = tmp; reverse_map[i] = s1[i]; } for(int i=0;i<s2.size();i++) if(hash_map.find(s2[i])!=hash_map.end()){ vector<int> tmp = hash_map[s2[i]]; for(int j = tmp.size()-1;j>=0;j--) map_arr.push_back(tmp[j]); } if(map_arr.size()==0) return "-1"; vector<int> dp(map_arr.size()+2); int maxlen = 1; dp[1] = map_arr[0]; vector<int> pre(map_arr.size()+2); fill(pre.begin(),pre.end(),-1); vector<int> path(map_arr.size()+2); path[0] = -1; vector<int> path_ans; string ans; for(int i = 1;i<map_arr.size();i++){ if(map_arr[i]>dp[maxlen]){ maxlen++; dp[maxlen] = map_arr[i]; pre[i] = path[maxlen-1]; path[maxlen] = i; }else{ int pos = lower_bound(dp.begin()+1, dp.begin() + maxlen , map_arr[i], less<int>()) - dp.begin(); dp[pos] = map_arr[i]; pre[i] = path[pos-1]; path[pos] = i; } } int i = path[maxlen]; while(i!=-1){ path_ans.push_back(map_arr[i]); i = pre[i]; } for(int i=path_ans.size()-1;i>=0;i--) ans+=reverse_map[path_ans[i]]; return ans; } };
将s1映射为一个上升序列,该映射函数设为f,则s3 = f(s2),该问题即为求s3的最长上升子序列。求出结果为s4,则原题目结果为f^-1(s4).关键问题在于s1中要是包含重复元素怎么处理?做法是将所有出现的位置均记录在一个序列里,然后在对s2做映射时,对该元素的序列降序。例如s1:a,b,c,a,d,c ;s2: c,a,b,c,d,a;则f为
a | 3,0 |
b | 1 |
c | 5,2 |
d | 4 |
则s3 = f(s2) = 5 2 3 0 1 5 2 4 3 0
s4 = 0 1 2 4
s5 = f^-1(s4) = a b c d