1. 程式人生 > >每日一題之 hiho227周 Longest Subsequence

每日一題之 hiho227周 Longest Subsequence

描述
You are given a set of N words W1, W2, … WN and a target string S. Find the longest word which is also a subsequence of S.

輸入
The first line contains an integer N. (1 <= N <= 10000)

The following N lines each contain a word Wi. (1 <= Σ|Wi| <= 100000)

The last line contains the string S. (1 <= |S| <= 100000)

輸出
The length of the longest word which is also a subsequence of S.

樣例輸入
3
a
ac
abc
acbc
樣例輸出
3

題意:

給n個詞,以及一個目標字串S,輸出這n個詞中是S的子序列且詞長度最大的那個詞的長度。這裡要注意的是子序列不要求連續的,但是如果是子串的話就要求是連續的。

思路:

一般我們判斷字串Wi是不是字串S的子序列,複雜度是O(|S|)的:

我們從左向右從S裡找到一個字元Wi[0],再向右找第一個Wi[1],再向右找第一個Wi[2]…,直到找到Wi最後一個字元或者S結束也沒有找完Wi。那麼Wi就不是S的子序列

不過如果我們能先計算出來f[i][c]表示S[i]之後,第一個字元c的位置,那麼上面的計算過程可以優化到O(|Wi|):

因為一旦我們找到S[i]是第一個Wi[0]之後,再向右的第一個Wi[1]的位置就是f[i][Wi[1]],再向右第一個Wi[2]的位置就是f[ f[i][Wi[1]] ][Wi[2]] …

而f陣列的計算可以通過從後向前掃描S,O(26 * |S|)計算出來。具體的轉移方程是
f [ i

] [ j ] = i + 1 , S [ i + 1 ] = j f[i][j] = i + 1, S[i+1] = j
f [ i ] [ j ] = f [ i + 1 ] [ j ] , S [ i + 1 ] j f[i][j] = f[i+1][j], S[i+1] \neq j
這裡 j 是代表26個字元中一個。

有了f之後,再依次計算Wi是不是S的子序列,總複雜度是O( Σ|Wi| )的。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>

using namespace std;

const int maxn = 1e5+7;

int f[maxn][30];

void init(string &S) {
	int len = S.length();
	memset(f,-1,sizeof(f));
	for (int i = len-1; i >= 0; --i) {
		for (int j = 0; j < 26; ++j) {
			if (S[i+1]-'a' == j) { 
				f[i][j] = i+1;
			}
			else 
				f[i][j] = f[i+1][j];
		}
	}
}

void solve(string &S, vector<string> &words) {
	init(S);
	int len = words.size();
	int slen = S.length();
	string word;
	int res = 0;
	for (int i = 0; i < len; ++i) {
		word = words[i];
		int tmp = 0;
		int wlen = word.length();
		int j;
		for (j = 0; j < slen; ++j) {
			if (word[0] == S[j]) {
				tmp = 1;
				break;
			}
		}
		if (tmp == 0) continue;
		int k = 1;
		while(k < wlen && f[j][word[k]-'a'] != -1) {
			++tmp;
			j = f[j][word[k]-'a'];
			++k;
		}
		if (tmp == wlen)
			res = max(res,tmp);
	}

	cout << res << endl;

}

int main() {

	int n;
	cin >> n;
	vector<string>words;
	string S,s;
	for (int i = 0; i < n; ++i) {
		cin >> s;
		words.push_back(s);
	}
	cin >> S;
	solve(S, words);

	return 0;
}