Friday, October 17, 2014

Minimum window substring

Leetcode link.

This is suppose to be an easy question since I have already read through stormrage's post and thought I have mastered every detail about this code. But eventually it took me almost 3 hours straight to figure out a nice and clean code.

There are several things that one should notice in designing a robust algorithm for this problem:

  1. loop invariant: count <= total required chars. (excessive chars not accounted). If count < total required chars, we are building the first matching window. thus shrinking left edge is not necessary. Else if count == total required chars, Current window is either a half finished first time window or perfect left edge window with "one extra required char on the right edge " window. In both cases we can start shrinking left edge.
  2. We do not have to write a separate code block to do first time window matching because either the first matching or second matching requires left shrinking. Thinking of S = "aab" and T = "b".
So eventually with some modifications I come up with the following code. Alas, always think carefully before you start coding.

string minWindow(string S, string T) {
    if(S.size() < T.size() || !T.size()) return *(new string);
    vector lmt(256);
    for(auto c:T) lmt[c]++;
    vector ct(256);
    
    int minLen = INT_MAX;
    string ret;
    
    int a0, a1, count;                              // left and right edge pointer.
    count = 0;
    for(a0 = 0, a1 = 0; a1 < S.size(); a1++) {      // do right edge expand at loop start
        if(!lmt[S[a1]]) continue;                   // invalid char, keep expanding
        if(ct[S[a1]] < lmt[S[a1]]) count++;         // char is needed now, increase count
        ct[S[a1]]++;                                // hasFound array+1
        
        if(count == T.size()) {                     // loop invariant met, now do shrinking
            for(;a0 < a1; a0++) {                   // shrinking....
                if(!lmt[S[a0]]) continue;           // invalid char, keep shrinking
                ct[S[a0]] --;                       // good char, try hasFound--
                                                    // before shrinking
                if(ct[S[a0]] < lmt[S[a0]]) {        // oops, should not delete this char.
                    ct[S[a0]]++;                    //   roll hasFound back.
                    break;                          //   don't move left edge pointer a0
                }                                   // it's ok to remove this char, keep
                                                    // shrinking
            }
            
            if(a1 - a0 + 1 < minLen) {              // one min window found. update
                minLen = a1-a0+1;
                ret = S.substr(a0, a1-a0+1);
            }
        }
    }
    
    if(minLen == INT_MAX) return *(new string);     // INT_MAX is acting as safeguard.
    return ret;
}

No comments:

Post a Comment