C.Two strings

本文介绍了一种解决特定字符串匹配问题的算法。该算法通过构建前后缀数组来确定字符串B中需要删除的最少连续字符数量,使得剩余部分成为字符串A的子序列。文章通过实例详细解释了算法的实现过程。
http://blog.youkuaiyun.com/sizaif/article/details/72849472
C. Two strings
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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 and make it empty.

Subsequence of string s is any such string that can be obtained by erasing zero or more characters (not necessarily consecutive) from string s.

Input

The 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 characters.

Output

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).

Examples
input
hi
bob
output
-
input
abca
accepted
output
ac
input
abacaba
abcdcba
output
abcba
Note

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.


123


不得不说CF的 题目 真是又爱又恨啊,  第一遍读上去,感觉像 公共子序列的问题,  ,看第二个示例,又不是,  晕啊晕,  

题目大意:     给你A 串 B 串  问 在 B串中删除x连续的串后,  剩下的 连在一起是A的子序列,

注意:  A 可以不连续,   只要B剩下的字符, A里面有就可以


用两个数组,  一个前缀,一个后缀,   记录 A串中 B的子序列长度,   然后 枚举A   从中选取 删除后缀减去前缀的部分;

选个最小的;    题目是 最小连续的B子串

 注意 赋初值的问题 以及 后缀最大的 要存最大值; 是为了删除串的作用

  1. #include <iostream>  
  2. #include <map>  
  3. #include <queue>  
  4. #include <string>  
  5. #include <algorithm>  
  6. #include <cmath>  
  7. #include <vector>  
  8. #include <cstring>  
  9. #include <stdio.h>  
  10.   
  11. using namespace std;  
  12.   
  13. typedef long long ll;  
  14. const int MAXN=1e5+155;  
  15. int pre[MAXN],suf[MAXN];//存前缀和后缀    相当于存 A的  对于B的子序列的长度  
  16.   
  17.   
  18. char a[MAXN],b[MAXN];  
  19. int main()  
  20. {  
  21.     while(~scanf("%s%s",a+1,b+1))  
  22.     {  
  23.         int len1=strlen(a+1);  
  24.         int len2=strlen(b+1);  
  25.         int last=0;  
  26.         // 不论是前缀还是后缀,  只要A 中有B的 某些串就可以 可以不连续,  例如A :abc   B: ac   B为A的子串  
  27.         for(int i=1;i<=len1;i++)  //赋初值  
  28.             pre[i]=len2,suf[i]=1;  
  29.         suf[len1+1] = len2+1;// 必须有 目的是为了删除子串的作用, pre[i-1]  
  30.         for(int i=1,j=1;i<=len1&&j<=len2;i++)  //这里是构造A的前缀  
  31.         {  
  32.             if(a[i]==b[j])// 相同记录前缀, 更新  
  33.             {  
  34.                 pre[i]=j;  
  35.                 last=j;  
  36.                 j++;  
  37.             }  
  38.             else  
  39.                 pre[i]=last;  //如果这个不相同,就等于前面的last  
  40.         }  
  41.         last=len2+1;  
  42.         for(int i=len1,j=len2;i>=1&&j>=1;i--)//构造A的后缀  
  43.         {  
  44.             if(a[i]==b[j])  
  45.             {  
  46.                 suf[i]=j;  
  47.                 last =j;  
  48.                 j--;  
  49.             }  
  50.             else  
  51.                 suf[i]=last;  
  52.         }  
  53.         int ans=len2+1, left=1,right=len2+1; //初始化答案为最大;  
  54.         for(int i=1;i<=len1+1;i++)//枚举所有的情况  
  55.         {  
  56.             if(pre[i-1]<suf[i]&&ans>suf[i]-pre[i-1])  
  57.             {  
  58.                 ans=suf[i]-pre[i-1];  
  59.                 left=pre[i-1];  
  60.                 right=suf[i];  
  61.             }  
  62.         }  
  63.         if(ans== len2+1 )  
  64.         {  
  65.             cout<<"-"<<endl;  
  66.             continue;  
  67.         }  
  68.         for(int i=1;i<=len2;i++)// 输出 删除后的b  
  69.         {  
  70.             if(i<=left||i>=right)  
  71.                 cout<<b[i];  
  72.         }  
  73.     }  
  74.     return 0;  
  75. }  
To solve this problem, we can use the sliding window approach again. Here's the algorithm: 1. Initialize two dictionaries: need and window. need stores the count of each character in t, and window stores the count of each character in the current window. 2. Initialize two pointers left and right to mark the current window, and two variables match and required to track the number of matched characters and the number of required characters respectively. 3. Initialize a variable min_len to a large value and a variable start to 0 to store the start index of the minimum window substring. 4. While the right pointer is less than the length of the string s: - If the character at s[right] is in need, add it to window and update match and required accordingly. - While all characters in need are included in window, update min_len and start accordingly, and remove the character at s[left] from window and update match and required accordingly. - Move the left pointer to the right. - Move the right pointer to the right. 5. Return the minimum window substring starting from index start and having length min_len, or the empty string if no such substring exists. Here's the Python code for the algorithm: ``` def min_window(s, t): need = {} for c in t: need[c] = need.get(c, 0) + 1 window = {} left = right = 0 match = 0 required = len(need) min_len = float('inf') start = 0 while right < len(s): if s[right] in need: window[s[right]] = window.get(s[right], 0) + 1 if window[s[right]] == need[s[right]]: match += 1 while match == required: if right - left + 1 < min_len: min_len = right - left + 1 start = left if s[left] in need: window[s[left]] -= 1 if window[s[left]] < need[s[left]]: match -= 1 left += 1 right += 1 return s[start:start+min_len] if min_len != float('inf') else "" ``` Example usage: ``` s = "ADOBECODEBANC" t = "ABC" print(min_window(s, t)) # Output: "BANC" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值