题目:
给定一个字符串source和一个目标字符串target,在字符串source中找到包括所有目标字符串字母的子串。
注意事项
如果在source中没有这样的子串,返回"",如果有多个这样的子串,返回起始位置最小的子串。
说明
在答案的子串中的字母在目标字符串中是否需要具有相同的顺序?
——不需要。
样例
给出source = "ADOBECODEBANC",target = "ABC" 满足要求的解 "BANC"
要求时间复杂度为O(n)
分析:采用哈希的思想,记录字母出现次数。
大小写字母的ASCII码不大于256,这样array['A']=3指A出现3次,array['B']=1指B出现了一次,以此类推,不能用常规意义上的定义array[0]=3表示A出现3次,这样就多了一层映射!故而数组的长度设置为256即可存放所有的字母。
首先预处理target,用256大小的整数数组tHash存储里面每个char出现的个数;
然后给定两个指标beg和end,一个移动start,也用一个256长的整数数组sHash记录从beg到end的这段字符串里面每个char出现的个数。如果sHash大于等于tHash,也就是说sHash里的每一位大于等于tHash里相应位置的值,找到当前start位置,为符合要求子串的起点,记录当前beg和end的长度,如果比已经记录的小,那么我们就选这个位最小窗口。记录beg和end。然后让start往前走一位。寻找下一个子串。 这里使用数组是取巧,也可以使用hashMap来记录,方法类似。
代码:
public class Solution { /* * @param source : A string * @param target: A string * @return: A string denote the minimum window, return "" if there is no such a string */ public String minWindow(String source , String target) { // write your code here // write your code here // write your code here int[] srcHash = new int[255]; //记录目标字符串每个字母出现次数 for(int i=0;i<target.length();i++){ srcHash[target.charAt(i)]++; } int start = 0,i=0,found =0; int[] dectHash = new int[255]; int begin = -1,end = source.length(),minLength = source.length(); for(start = i=0;i<source.length();i++){ dectHash[source.charAt(i)] ++; if(dectHash[source.charAt(i)]<=srcHash[source.charAt(i)]) found++; //若没有到数,添加1 if(found == target.length()){ //找到了能包含target的字符串,然后去掉前面的无用字符串 while(start < i && dectHash[source.charAt(start)]>srcHash[source.charAt(start)]){ dectHash[source.charAt(start)]--; start++; } // 这时候start指向该子串开头的字母,判断该子串长度 if(i-start < minLength){ minLength = i-start; begin = start; end = i; } //从下一个字符串开始查找 dectHash[source.charAt(start)]--; found--; start++; } } return begin==-1?"":source.substring(begin,end+1); } }