LintCode 最小子串覆盖 Hash表
最近秋招之路告一段落,玩了好几天。。。
今天咸鱼般的水了一题,花了些时间= =
题目:原题地址
给定一个字符串source和一个目标字符串target,在字符串source中找到包括所有目标字符串字母的子串。
注意事项
如果在source中没有这样的子串,返回"",如果有多个这样的子串,返回起始位置最小的子串。
说明
在答案的子串中的字母在目标字符串中是否需要具有相同的顺序?
——不需要。
样例
给出source = "ADOBECODEBANC",target = "ABC" 满足要求的解 "BANC"
挑战
要求时间复杂度为O(n)
解题思路:
用两个map,sMap表示原串中,需要比较的字符出现的次数 tMap表示目标串中,需要比较的字符出现的次数
当tMap里的数据都小于等于sMap时,即找到了结果。
而难点就是怎样在O(n)的复杂度内完成要求,并且找到最小的结果
时间复杂度要求O(n),可是两个字符串是必须要遍历的,那么就需要在遍历字符串的过程中完成操作,那么我们可以在遍历的过程中,找出一次次满足结果的解,
最后取最小的就行了,这样便能控制在O(n)的时间内
详细注释和代码如下:
public String minWindow(String source, String target) { int len1 = source.length();// 原串的长度 int len2 = target.length();// 目标串长度 if (len1 < len2)//条件不满足,直接返回"" return ""; String result = "";//用于记录结果 int minLen = len1 + 1;//用于记录最小长度 Map<Character, Integer> sMap = new HashMap<Character, Integer>();//用于原串的哈希表 Map<Character, Integer> tMap = new HashMap<Character, Integer>();//用于目标串的哈希表 for (int i = 0; i < len2; i++) {//将目标串中,出现字符的个数放入tMap if (tMap.containsKey(target.charAt(i))) { tMap.put(target.charAt(i), tMap.get(target.charAt(i)) + 1); } else { tMap.put(target.charAt(i), 1); } } int count = 0;//用于记录放入sMap的个数,目的是找到第一个成立的result。和以后出现的result for (int i = 0; i < len1; i++) { int Len = 0; //依次比较原串与目标串。同步两个Map里的数据。用count来找出现结果的时候(count==len2) if (tMap.containsKey(source.charAt(i))) { if (sMap.containsKey(source.charAt(i))) { if (sMap.get(source.charAt(i)) < tMap.get(source.charAt(i))) { count++; } sMap.put(source.charAt(i), sMap.get(source.charAt(i)) + 1); } else { sMap.put(source.charAt(i), 1); count++; } } if (count == len2) {//此时出现了结果 char c = source.charAt(Len); //找到结果的起始位置 while (!sMap.containsKey(c) || sMap.get(c) > tMap.get(c)) { if (sMap.containsKey(c) && sMap.get(c) > tMap.get(c)) sMap.put(c, sMap.get(c) - 1); c = source.charAt(++Len);//len的长度,即为此时result的开始位置 } //得到最终结果 if (i - Len + 1 < minLen) { result = source.substring(Len, i + 1); minLen = i - Len + 1; } } } return result; }
最后附上一张AC图~