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

Minimum Window Substring
Time Limit: 1000 MSMemory Limit: 65535 K
Total Submit: 51(17 users)Total Accepted: 28(14 users)Rating: Special Judge: No
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");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值