上海交大2019考研機試第一題:以時間複雜度爲nlogn的算法解決最長公共子序列(LCS)問題

給出兩個數字序列,求最長公共子序列(LCS)。 保證一個序列中所有元素都不重複,第一行給定一個n 爲序列的長度,第二第三行爲兩個序列。
其中 60% 的用例 n<=1000,所有用例保證 n<= 1000000
Sample Input
5
1 2 3 4 5
1 2 3 4 5
Sample Output
5
Sample Input
5
1 2 3 5 4
1 2 3 4 5
Sample Output
4

提煉題目:此題要求以時間複雜度爲nlogn的算法解決最長公共子序列問題

  • 條件:所給兩個序列中均沒有重複元素
  • 要求:數據規模爲1e6,要求在10s內完成,亦即常規n^2複雜度不能解決此題
  • 解法:首先,由於序列中沒有重複元素,可以把一個字符串按順序映射爲 1,2,3,4,……並用數組記錄下來,這樣字符串1就變成了一個連續遞增的字符串;然後,再講字符串爲按照字符串1得到的映射字符數組映射爲新的字符串3;如此,問題即轉化爲在字符串3中尋找1,2,3,……這樣連續遞增的字符子串的最大長度;顯然,在字符串3中尋找連續遞增字符串的最大長度,則最長公共子序列問題(LCS)即被巧妙轉化爲最長遞增子序列問題(LIS)。LIS的動態規劃算法的改進算法的時間複雜度即爲nlogn。
  • 代碼如下
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <climits>

using namespace std;
const int INF = INT_MIN;
const int MAXN = 1e6+1;
int seq[MAXN];
int mapTable[MAXN];
int minRearElem[MAXN];
int len;
int main() {
	int n;
	while (scanf("%d", &n) != EOF) {
		memset(mapTable, 0, sizeof(mapTable));
		int x;
		for (int i = 1; i <= n; i++) {
			scanf("%d", &x);
			mapTable[x] = i;
		}
		for (int i = 1; i <= n; i++) {
			scanf("%d", &x);
			seq[i] = mapTable[x];
		}
		len = 0;
		minRearElem[len] = INF;
		for (int i = 1; i <= n; i++) {
			if (seq[i] >= minRearElem[len]) {
				len++;
				minRearElem[len] = seq[i];
			}
			else {
				int low = 1, high = len;
				while (low < high) {
					int mid = (low + high) / 2;
					if (minRearElem[mid] > seq[i]) {
						high = mid-1;
					}
					else if (minRearElem[mid] < seq[i]) {
						low = mid + 1;
					}
					else {
						break;
					}
				}
				minRearElem[low] = seq[i];
			}
		}
		printf("%d\n", len);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章