hrbust 1758 Minimum Window Substring【尺取法】好题

来源:互联网 发布:中国阶级 知乎 编辑:程序博客网 时间:2024/05/12 10:45

Minimum Window SubstringTime Limit: 1000 MSMemory Limit: 65535 KTotal Submit: 51(17 users)Total Accepted: 28(14 users)Rating: Special Judge: NoDescription

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
ADOBECODEBANCABCacbdbaabaabdadobecodebancbbcaaabc203838534736761996179497200837746ZHEXOMNHPRWMAJFPSUCYFZXUNLNRRUYUXdptpeaevzsykxnfurfbqcxdqkujgtcurnuLY7JdYK1810x95bT3LyPx7V37iLjYJx8w_J)u^^@gsWoXnTB*@CWAh./k9d3|%^3w
Sample Output
BANCdbaabca4736YFZXUnfurJdYK1810xw_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");    }}


0 0
原创粉丝点击