问题:
设计一个O(n^2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。
方法一:最长公共子序列。
思路:1:将数组a复制到b;
2:对b排序;
3:对数组b去重(注意去重是必要的,因为要求单调递增),这里利用hash表去重。
4:求a, b数组的最长公共子序列。
求最长公共子序列方法见 https://blog.csdn.net/m0_38015368/article/details/79835163
代码:
#include <bits/stdc++.h> using namespace std; int a[1024]; //原数组 int b[1024]; //排序后数组 int ans[1024][1024]; //记录 c[i][j] 的值是有哪个子问题得到 int c[1024][1024]; //最长子序列长度 int n; //数组长度 int m; //去重后的长度 void LCS(int i, int j) { if(i == 0 || j == 0) return; else if(ans[i][j] == 1) { LCS(i - 1, j - 1); cout << a[i] << " "; } else if(ans[i][j] == 2) { LCS(i - 1, j); } else { LCS(i, j - 1); } } void LCSLegth() { memset(ans, 0, sizeof(ans)); memset(c, 0, sizeof(c)); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(a[i] == b[j]) { c[i][j] = c[i - 1][j - 1] + 1; ans[i][j] = 1; } else if(c[i - 1][j] > c[i][j - 1]) { c[i][j] = c[i - 1][j]; ans[i][j] = 2; } else { c[i][j] = c[i][j - 1]; ans[i][j] = 3; } } } } void HashTable() { int max_ = b[n]; m = 0; int *p = new int(max_); memset(p, 0, sizeof(p)); for(int i = 1; i <= n; ++i) { p[b[i]] = 1; } memset(b, 0, sizeof(b)); for(int i = 0; i <= max_; ++i) { if(p[i] == 1) b[++m] = i; } delete []p; p = NULL; } void solve() { sort(b + 1, b + n); HashTable(); //去重 // for(int i = 1; i <= m; ++i) // cout << b[i] << " "; // cout << endl; LCSLegth(); LCS(n, m); } void inPut() { scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); b[i] = a[i]; } } int main() { inPut(); solve(); }
方法二