Minimum Window Substring | ||||||
| ||||||
Description | ||||||
Given a string S and a string T, find the minimum window in S which will contain all the characters. For example, S = "ADOBECODEBANC" T = "ABC" Minimum window is "BANC". Note: If there are multiple such windows, you are guaranteed the window with the shortest length and first appeared in the string S. | ||||||
Input | ||||||
There are multiple test cases, processing to the end-of-file. For each case: Line 1: This line contains string S. Line 2: This line contains string T. The string contains printable characters except space (visible characters). The length of the string is not less than 1 and not greater than 100,000. | ||||||
Output | ||||||
For each case: Output one line, contains the minimum window substring. If there is no such window in S that covers all characters in T, output the empty string "". | ||||||
Sample Input | ||||||
ADOBECODEBANC ABC acbdbaab aabd adobecodebancbbcaa abc 203838534736761996179497200837 746 ZHEXOMNHPRWMAJFPSUCYFZXUNLNRRU YUX dptpeaevzsykxnfurfbqcxdqkujgtc urn uLY7JdYK1810x95bT3LyPx7V37iLjY Jx8 w_J)u^^@gsWoXnTB*@CWAh./k9d3|% ^3w | ||||||
Sample Output | ||||||
BANC dbaa bca 4736 YFZXU nfur JdYK1810x w_J)u^^@gsWoXnTB*@CWAh./k9d3 |
题目大意:
给你两个字符串,让你在第一个串中找最短的子串,使得这个子串包含所有第二个串中的元素,并且要求个数需要大于等于,但是不要求相对位子相同。
如果找不到,输出一个空串。
思路:
1、尺取法,本题和Poj 3320有异曲同工之处,不过这个题相对难了一点点,另外吐槽一下理工OJ,能不用STL就表用STL.....会迷之TLE。
2、
①我们首先预处理出串2一共有多少种字符,记做contz,同时将每个字符的数量记录到s【i】中。
②那么我们设定区间sum【1,t】=x表示从串1从第一个字符到第t个字符,其中有x个元素完全和串2相同(包括数量)
如果设定sum【1,t】==contz&&sum【1,t-1】<contz;
那么如果还有:sum【2,t】<contz
那么如果再有:sum【2,t】==contz
那么一定有tt>t
3、那么根据以上特性,我们考虑设定一个起点l,一个终点r。一个值sum,表示从起点l到终点r中已经包含了多少种字符。算法过程如下:
①初始化l=sum=s=0;并且设定ss【i】表示ASCII码为i的这个字符出现了多少次(在区间内)。
②如果r<n,跳③,否则结束过程,输出最优解。
③如果r<n:
情况1:如果当前字符在串2中没有出现过,那么直接r++;继续此步骤
情况2:如果当前字符在串2中出现过,那么对应ss【a【r】】++;此时如果ss【a【r】】==s【a【r】】,那么对应sum++,此时如果sum==contz,跳④,否则继续。
④如果l<r:
情况1:如果当前字符串在串2中没有出现过,那么l++;继续此步骤
情况2:如果当前字符串在串2中出现过,那么对应ss【a【r】】--;此时如果ss【a【r】】<s【a【r】】,那么对应sum--,并且跳⑤,否则继续
⑤对应当前区间左端点l之后可能会有多个不相干的字符,那么我们需要处理掉:while(l<r&&s【a【left】==0】)left++;处理完毕之后,以此时的l和r,跳②
整个过程中如果:sum【l,r】==contz,我们就维护一下最优解。
4、思路构建的差不多了,注意严谨一些,写好代码即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<map>
#include<iostream>
using namespace std;
char a[1000040];
char b[1000040];
int s[4000];
int ss[4000];
int main()
{
while(~scanf("%s%s",a,b))
{
memset(s,0,sizeof(s));
memset(ss,0,sizeof(ss));
int lena=strlen(a);
int lenb=strlen(b);
int contz=0;
for(int i=0;i<lenb;i++)
{
if(s[b[i]]==0)s[b[i]]=1,contz++;
else s[b[i]]++;
}
int sum=0;
int ansl=1,ansr=0,minn=0x3f3f3f3f;
int left=0;
while(1)
{
for(int i=0;i<lena;i++)
{
if(s[a[i]]==0)continue;
else
{
ss[a[i]]++;
if(ss[a[i]]==s[a[i]])sum++;
if(sum==contz)
{
if(minn>i-left)
{
minn=i-left;
ansl=left;
ansr=i;
}
for(int j=left;j<i;j++)
{
if(s[a[j]]==0)
{
left++;
if(i-left<minn)
{
minn=i-left;
ansl=left;
ansr=i;
}
}
else
{
ss[a[j]]--;
left++;
if(ss[a[j]]<s[a[j]])
{
sum--;
while(s[a[left]]==0&&left<i)left++;
break;
}
else
{
if(i-left<minn) if(minn>i-left)
{
minn=i-left;
ansl=left;
ansr=i;
}
}
}
}
}
}
}
break;
}
for(int i=ansl;i<=ansr;i++)
{
printf("%c",a[i]);
}
printf("\n");
}
}