LeetCode – Minimum Window Substring (Java)

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

For example, S = “ADOBECODEBANC”, T = “ABC”, Minimum window is “BANC”.

Java Solution

public String minWindow(String s, String t) {
    HashMap<Character, Integer> goal = new HashMap<>();
    int goalSize = t.length();
    int minLen = Integer.MAX_VALUE;
    String result = "";
 
    //target dictionary
    for(int k=0; k<t.length(); k++){
        goal.put(t.charAt(k), goal.getOrDefault(t.charAt(k), 0)+1);
    }
 
    int i=0;
    int total=0;
    HashMap<Character, Integer> map = new HashMap<>();
    for(int j=0; j<s.length(); j++){
        char c = s.charAt(j);
        if(!goal.containsKey(c)){
            continue;
        }
 
        //if c is a target character in the goal, and count is < goal, increase the total
        int count = map.getOrDefault(c, 0);
        if(count<goal.get(c)){
            total++;
        }
 
        map.put(c, count+1);
 
        //when total reaches the goal, trim from left until no more chars can be trimmed.
        if(total==goalSize){
            while(!goal.containsKey(s.charAt(i)) || map.get(s.charAt(i))>goal.get(s.charAt(i))){
                char pc = s.charAt(i);
                if(goal.containsKey(pc) && map.get(pc)>goal.get(pc)){
                    map.put(pc, map.get(pc)-1);
                }
 
                i++;
            }
 
            if(minLen>j-i+1){
                    minLen = j-i+1;
                    result = s.substring(i, j+1);
            }
        }            
    }
 
    return result;
}

11 thoughts on “LeetCode – Minimum Window Substring (Java)”

  1. public String minimumWindowSubString(String s, String t) {

    if (s == null || t == null || s.length() < t.length()) return null;

    int sLen = s.length();

    int tLen = t.length();

    if (tLen < 1) return s;

    LinkedList locations = new LinkedList();

    LinkedList theT = new LinkedList();

    HashMap keyMap = new HashMap();

    int[] minWindow = new int[]{0, 0};

    for (char c : t.toCharArray()) {

    keyMap.put(c, keyMap.getOrDefault(c, 0) + 1);

    }

    int count = tLen;

    for (int i = 0; i 0) {

    keyMap.put(c, keyMap.get(c) - 1);

    locations.add(i);

    theT.add(c);

    count--;

    if (count == 0) {

    int cursize = minWindow[1] - minWindow[0];

    if (cursize == 0 || (cursize > (locations.get(tLen - 1) - locations.get(0)))) {

    minWindow[0] = locations.get(0);

    minWindow[1] = locations.get(tLen - 1);

    if (sLen - i < minWindow[1] - minWindow[0]) break;

    }

    keyMap.put(theT.getFirst(), 1);

    locations.removeFirst();

    theT.removeFirst();

    count = 1;

    }

    } else {

    int ind = theT.indexOf(c);

    locations.remove(ind);

    theT.remove(ind);

    locations.add(i);

    theT.add(c);

    }

    }

    }

    return s.substring(minWindow[0], minWindow[1] + 1);

    }

  2. This code FAILS for this example:

    Input string1: “this is a test string”
    Input string2: “tist”
    Output string: “t stri”

  3. Faster and easier to understand solution: (O(n))

    public static String shortestWindow(String s, String t) {
    if (s == null || s == “” || t == null || t == “”) {
    return null;
    }
    LinkedHashMap map = new LinkedHashMap();
    String shortest = null;
    for (int i = 0; i (i – map.entrySet().iterator()
    .next().getValue())) {
    shortest = s.substring(map.entrySet().iterator().next()
    .getValue(), i+1);
    }
    map.clear();
    }

    }
    return shortest;
    }

  4. I think the complexity is O(n^2), since there are n(n+1)/2. obviously the upper bound is not 2*n, So it is not O(n). I searched online, lots of guys claim complexity is O(n^2). To me that is not right.

  5. The loop for
    count == t.length() can be modified to count == t.length() && map.containsKey(c)
    for more optimized checking

  6. This runs in O(n log n). but the idea is easier to understand.

    count through word till you’ve gotten all the characters in your target substring, and then compare the length to last result.

    import java.util.*;

    public class shortest_window{

    public static void main(String[] args){

    String word = "ADOBECODEBANC";

    String target = "ABC";

    System.out.println(solution(word, target));

    }

    public static String solution(String word, String targ){

    if(word==null || word.length() < 1 ) return "";

    if(targ==null || targ.length() < 1) return "";

    char arr = new targ.toCharArray();

    String shortest = word;

    for(int i =0; i < word.length(); i++){

    String temp = "";

    ArrayList target = new ArrayList();

    for(Character c: arr){

    target.add((Character)c);

    }

    for(int j = i; j temp.length()) shortest = temp;

    break;

    }

    }

    }

    return shortest;

    }

    }

  7. No, it doesn’t need to do it. Although it is a good idea to decrease count by 1. Then taking one character out of the map and increase left by 1.
    S = “ADOBECODEBANC”, T = “ABC”.
    Think about this case, first we find “ADOBEC” then when count == t.length(), left is A since we can not drop any of character then we move left to D and move A from map and count–. This is the method that you talk about.
    But we can keep count as 3 and without moving left, we still move i to next A,
    then it becomes “ADOBECODEBA”, here count == 3 == t.length(), but now we can move left from the first A to C, it becomes “CODEBA”.
    See, that is the reason we don’t need to decrease count by 1.

  8. count == t.length()
    After doing the operation when you meet your desired count of characters in T, you need to decrease count by 1 as you are removing character one by one. AT the end when it will find the desired smallest length it would take one character out of the map and hence it should decrease that count by 1 as well.

Leave a Comment