好题。字符串。线性时间。
我认为第一次拿到这个题的人应该不会知道该怎么做吧,要么就是我太弱了。。先搞清楚这个题要求的是什么。从一个长字符串中找一个字串,这个字串中的字符全然包括了另一个给定目标串中的字符,且这个字串的长度要求最小。
另一个很重要的简化,题干指明了要求这样的最短字串仅仅有一个,这个限制事实上暗示了这道题的总体思路。仅仅要找到一个长串,然后缩减到不能缩减就可以。
从题目的要求出发能够发现,这道题对于字符串中字符的顺序是没有要求的。因此能够非常自然的想到用hash表来保存目标串中的每一个字符的个数,然后在源字符串中找到一个字串。包括的字符个数大于等于目标串中的就可以。难就难在怎么实现这个功能。
能够把目标串中每一个字符的个数作为它的需求。每当在长字符串中找到了一个字符,这个字符在目标串中存在。那么需求应该降低1。当需求等于0的时候,表示到眼下为止。长字符串中的字符能够恰好满足目标串中这个字符的需求了。假设一个目标串字符的需求变成了负值,说明在当前长度下,在长字符串中对这个字符的供应过剩了。为了描写叙述简便,我定义当长字符串在目标串对这个字符的需求为正时提供了这个字符,为满足了刚性需求,否者是供应过剩。接下来另一个问题,如何知道目标串被全然满足了呢?你当然能够去逐个的扫描需求是不是都变成非正的了,可是另一个更加简单的方法,那就是把目标串的长度看做是总需求,当满足刚性需求时,总需求减1,当总需求变成0时,说明目标串被满足了。
上面描写叙述的过程在长字符串中找到了一个字串,能够全然满足目标串,但并不保证是最短的,由于非常多字符在其它字符没得到满足时已经供应过剩了,如何把这部分多余的去掉呢?从起点開始往后扫秒长字符串。假设当前字符根本不存在于目标串中,能够直接pass。假设存在于目标串中,且供应过剩了。那么这个字符能够从我们的字串中去掉,相当于我们的字串缩短了。可是要记得把需求量++。由于供应量降低了。知道一个字符,它既存在于目标串中,且他的需求量正好是等于0的,我们就得停下了,由于这时候的所有是刚性需求,不能再降低供应了。
代码例如以下,并没有最优化。只是思路是写出来了。
class Solution { public: string minWindow(string S, string T) { int ct1[270], ct2[270]; int mlen1 = S.length(); int mlen2 = T.length(); memset(ct1, 0, sizeof(ct1)); memset(ct2, 0, sizeof(ct2)); int hole = mlen2, minSize = INT_MAX, start = 0, minstart; for(int i=0;i<mlen2;i++){ ct1[T[i]]++; ct2[T[i]]++; } for(int i=0;i<mlen1;i++){ if(ct2[S[i]]>0){ ct1[S[i]]--; if(ct1[S[i]]>=0) hole--; } if(hole == 0){ while(start<mlen1){ if(ct2[S[start]]>0){ if(ct1[S[start]]<0) ct1[S[start]]++; else break; } start++; } if(minSize>i-start+1){ minSize = i-start+1; minstart = start; } } } if(minSize == INT_MAX) return ""; return S.substr(minstart, minSize); } };