標籤:c++ leetcode 演算法
好題,字串,線性時間。
我覺得第一次拿到這個題的人應該不會知道該怎麼做吧,要麼就是我太弱了。。先搞清楚這個題要求的是什麼。從一個長字串中找一個字串,這個字串中的字元完全包含了另一個給定目標串中的字元,且這個字串的長度要求最小。還有一個非常重要的簡化,題幹指明了要求這種最短字串只有一個,這個限制其實暗示了這道題的整體思路,只要找到一個長串,然後縮減到不能縮減即可。
從題目的要求出發可以發現,這道題對於字串中字元的順序是沒有要求的,因此可以很自然的想到用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); }};