二分 + 預處理前綴後綴 技巧題
You are given two strings a and b. You have to remove the minimum possible number of consecutive (standing one after another) characters from string b in such a way that it becomes a subsequence of string a. It can happen that you will not need to remove any characters at all, or maybe you will have to remove all of the characters from b
Subsequence of string s is any such string that can be obtained by erasing zero or more characters (not necessarily consecutive) from string s.
InputThe first line contains string a, and the second line — string b. Both of these strings are nonempty and consist of lowercase letters of English alphabet. The length of each string is no bigger than 105
On the first line output a subsequence of string a, obtained from b by erasing the minimum number of consecutive characters.
If the answer consists of zero characters, output ?-? (a minus sign).
Example InputhiOutput
bob
-Input
abcaOutput
accepted
acInput
abacaba
abcdcba
abcbaNote
In the first example strings a and b don‘t share any symbols, so the longest string that you can get is empty.
In the second example ac is a subsequence of a, and at the same time you can obtain it by erasing consecutive symbols cepted from string b.
題目分析 :
給出兩個字符串,刪除第二個字符串中的一些連續的字符,且要求剩下的字符是上面串的子串。
思路分析 :
首先上來先想一個最暴力的思路,枚舉刪除字符串的長度,枚舉刪除的起點,再將剩下的字符串去匹配,雙指針,復雜度是 n^3 , 首先比較容易想到的一個地方優化,就是枚舉長度的時候我們可以去二分,復雜度為 logn ,但是僅憑這是不夠的,我們看一下字符串匹配那,是不是感覺匹配的過程中有很多匹配過程是重復的,那麽這裏肯定就是可以優化的,當刪除一個長度的字符串後,剩下的串一定是都要留下的,且可以看成一個前綴和一個後綴,那麽我們就可以預處理出全部可能的前綴以及後綴,新開兩個數組,記錄的每個位置對應在上面串中的哪個位置上,那麽總的復雜度就是 n*logn
代碼示例 :
#define ll long long const int maxn = 1e5+5; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; char pre[maxn], s[maxn]; int a[maxn], b[maxn]; int len1, len2; int start = -1, len; bool check(int lenn) { int p = lenn+1; int sign = 0; if (b[p]) {start = 1; len = lenn; sign = 1;} p = len2 - lenn; if (a[p]) {start = p+1; len = lenn; sign = 1;} //printf("**** %d %d\n", start, len); for(int i = 2; i <= len2-lenn; i++){ int ss = i-1, ee = i+lenn; if (!a[ss]) break; if (a[ss] < b[ee]) {start = i; len = lenn; sign = 1;} } if (sign) return true; else return false; } void fun() { int l = 0, r = len2; while(l <= r) { int mid = (l + r) >> 1; if (check(mid)) r = mid - 1; else l = mid + 1; //printf("***** %d %d %d %d %d\n", start, len, mid, l, r); } } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); scanf("%s", pre+1); scanf("%s", s+1); len1 = strlen(pre+1); len2 = strlen(s + 1); int p = 1; for(int i = 1; i <= len2; i++){ for(int j = p; j <= len1; j++){ if (s[i] == pre[j]) { a[i] = j; p = j+1; break; } } if (!a[i]) break; } p = len1; for(int i = len2; i >= 1; i--){ for(int j = p; j >= 1; j--){ if (s[i] == pre[j]) { b[i] = j; p = j-1; break; } } if (!b[i]) break; } fun(); //printf("%d %d\n", start, len); if (start == -1) {printf("-\n"); return 0;} for(int i = 1; i < start; i++) printf("%c", s[i]); for(int i = start+len; i <= len2; i++) printf("%c", s[i]); printf("\n"); //for(int i = 1; i <= len2; i++) printf("%d ", b[i]); return 0; }
二分 + 預處理前綴後綴 技巧題