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"
.
Note:
If there is no such window in S that covers all characters in T, return the empty string ""
.
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
在时间复杂度为O(n)的前提下,求出S中包含T的所有字母的最小字串。
第一次的做法,先用一个256大小的数组记录t中的字母。然后找到每一个符合条件的字符串,比较大小,最后果然超时。
public class Solution { public String minWindow(String s, String t) { int len1 = s.length(),len2 = t.length(); int[] tt = new int[256]; for( int i = 0;i<len2;i++) tt[t.charAt(i)]++; int[] t2 = tt.clone(); int num = 0,start = 0,end = 0,length = 0; int more = len1; for( int i = 0;i<len1;i++){ if( t2[s.charAt(i)] > 0){ more = length == 0?len1:length-len2; for( int j = i;j<len1;j++){ if( t2[s.charAt(j)] > 0){ num++; t2[s.charAt(j)]--; }else{ more--; if( more == 0) break; } if( num == len2 ){ if( length == 0 || (j-i+1) < length ) { start = i; end = j; length = end - start+1; more = length - len2; } t2 = tt.clone(); num = 0; break; } } t2 = tt.clone(); num = 0; } if( length == len2 ) break; } if( length == 0 ) return ""; char[] result = new char[length]; for( int i = 0;i<length;i++) result[i] = s.charAt(i+start); return String.valueOf(result); } }
然后改进一下,两个记录点left,right 都从左到右,right每走一次就在loc数组中记录该字母,并且看此时(left至right)是否包括了所有字母,如果包括,那么找出从left到right之间最小的一组。
速度还算可以。
public class Solution { public boolean cover(int[] a,int[] b){ for( int i = 0;i<256;i++) if( a[i] < b[i]) return false; return true; } public String minWindow(String s, String t) { int len1 = s.length(); int len2 = t.length(); int[] pos = new int[256]; for( int i = 0;i<len2;i++) pos[t.charAt(i)]++; int[] loc = new int[256]; int min = len1+1,start = 0,end = 0; for( int left = 0,right = 0;right < len1;right++){ loc[s.charAt(right)]++; if( !cover(loc,pos) ) continue; while( left <= right ){ char ch = s.charAt(left); if( pos[ch] == loc[ch] ) break; loc[ch]--; left++; } if( right-left < min ){ min = right-left; start = left; end = right; } } if( min == len1+1) return ""; char[] result = new char[min+1]; for( int i = start,j = 0;i<=end;i++,j++) result[j] = s.charAt(i); return String.valueOf(result); }}
发现每次需要判断一次cover浪费了许多时间,那么加入num变量,记录当前left到right之间,有多少已经命中了的字母。这样速度得到进一步提升。
public class Solution { public String minWindow(String s, String t) { int len1 = s.length(); int len2 = t.length(); if( len1 == 0 || len2 == 0) return ""; int[] pos = new int[256]; for( int i = 0;i<len2;i++) pos[t.charAt(i)]++; int[] loc = new int[256]; int min = len1+1,start = 0,end = 0,num = 0; int left = 0,right = 0; while( right < len1 ){ if( num < len2 ){ char ch = s.charAt(right); if( pos[ch] > 0){ loc[ch]++; if( loc[ch] <= pos[ch] ) num++; } right++; } while( num == len2 ){ if( min > (right-left)){ min = right-left; start = left; end = right; } char ch = s.charAt(left); if( loc[ch] == 0 ) left++; else if( loc[ch] > pos[ch]){ left++; loc[ch]--; }else{ num--; left++; loc[ch]--; } } } if( min == len1+1) return ""; char[] result = new char[min]; for( int i = start,j = 0;i<end;i++,j++) result[j] = s.charAt(i); return String.valueOf(result); } }
还可以在进行一点优化,就是将String转变成char[]这样在数量比较多的时候,会有速度的提升,会基本达到最快
只是加入char[] s_array = s.toCharArray() 以及将 s.charAt(i)变为 s_array[i]。
代码改动不大,就不再是上传一次了。