题目传送门
解题思路:
先是朴素做法,f[i][j]表示字符串A前i位和字符串B前j位的最长公共子序列,
当a[i] == b[j]时,f[i][j]=f[i-1][j-1] + 1; 如果不相等,f[i][j]=max(f[i-1[j],f[i][j-1);
时间复杂度是O(nm)的,近似O(n^2).
1 #include<iostream> 2 using namespace std; 3 4 int n,a[100001],b[100001],f[1001][1001]; 5 6 int main() { 7 cin >> n; 8 for(int i = 1;i <= n; i++) 9 cin >> a[i]; 10 for(int i = 1;i <= n; i++) 11 cin >> b[i]; 12 for(int i = 1;i <= n; i++) 13 for(int x = 1;x <= n; x++) 14 if(a[i] == b[x]) 15 f[i][x] = max(f[i-1][x-1] + 1, f[i][x]); 16 else 17 f[i][x] = max(f[i-1][x], f[i][x-1]); 18 cout << f[n][n] <<endl; 19 return 0; 20 }
以上做法对于本题只能的50分,所以就要想办法优化,怎么优化呢?
来一个c数组,其中c[i]存的是a[i]在b中的位置,举个例子:
a: 1 3 4 5 2 7
b: 2 4 5 1 7 3
c: 4 6 2 3 1 5
然后在c中求最长上升子序列,即为答案
时间复杂度为O(n log n)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 5 using namespace std; 6 7 int n,c[100001],f[100001],len; 8 struct kkk{ 9 int o,p; 10 }a[100001],b[100001]; 11 12 inline bool cmp(kkk s,kkk d) { 13 return s.o < d.o; 14 } 15 16 int main() { 17 scanf("%d",&n); 18 for(int i = 1;i <= n; i++) { 19 scanf("%d",&a[i].o); 20 a[i].p = b[i].p = i; 21 } 22 for(int i = 1;i <= n; i++) 23 scanf("%d",&b[i].o); 24 sort(a+1,a+n+1,cmp); 25 sort(b+1,b+n+1,cmp); 26 for(int i = 1;i <= n; i++) 27 c[a[i].p] = b[i].p; 28 for(int i = 1;i <= n; i++) { 29 if(c[i] > f[len]) 30 f[++len] = c[i]; 31 else { 32 int u = lower_bound(f+1,f+len+1,c[i]) - f; 33 f[u] = c[i]; 34 } 35 } 36 printf("%d",len); 37 return 0; 38 }