题目
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC" 输出: "BANC" 说明: 如果 S 中不存这样的子串,则返回空字符串 ""。 如果 S 中存在这样的子串,我们保证它是唯一的答案。
题解
解题思路来自于参考文章。本题采用一种高级双指针的滑动窗口法+哈希法进行求解。一般滑动窗口法适用于求解字符串匹配问题。具体解法见代码注释。
class Solution { public String minWindow(String s, String t) { /* 参考网上求解: 本题采用滑动窗口法进行求解,利用左右指针维护窗口大小,具体算法流程如下: 1.初始化左右指针left=right=0,利用双指针法得到一个窗口 2.不断增加right值以向右滑动窗口,直到窗口中的字符串符合要求 3.停止右指针的滑动,开始增加left指针值来缩小窗口大小,直到窗口中的字符串不符合题目要求为止,同时每次滑动left指针都记录好相关值以更新结果 4.重复2、3步直到right到达被查找字符串末尾 //注意这里用Integer作为计数值会出现bug,他是个对象,当用==判断时,他会判断地址,因为Integer只会缓存-128~127之间的数值,所以当超过这个区间的值后,就会new一个对象,出现地址不一致 */ if(s.length() < t.length()){ return ""; } int left = 0; int right = 0; Map<Character, Integer> need = new HashMap<>(); Map<Character, Integer> window = new HashMap<>(); int len = 0; int minLen = Integer.MAX_VALUE; //记录最小长度 int start = 0; //记录最小长度在被查找字符串中的起始位置 for(int i = 0; i < t.length(); ++i){ int count = need.getOrDefault(t.charAt(i), 0); need.put(t.charAt(i), count + 1); } while(right < s.length()){ char c = s.charAt(right); if(need.containsKey(c)){ int count = window.getOrDefault(c, 0); window.put(c, count + 1); if(window.get(c).intValue() == need.get(c).intValue()){ //这里如果不进行intValue()的话,会通过不了最后一个测试用例,原因见上面 len++; //代表匹配了一个字符 } } right++; while(len == need.size()){ //开始上面的第3步,进行缩小滑动窗口 if(right - left < minLen){ //更新好最值 minLen = right - left; start = left; } char c1 = s.charAt(left); if(need.containsKey(c1)){ int count = window.get(c1); window.put(c1, count - 1); if(window.get(c1).intValue() < need.get(c1).intValue()){ len--; } } left++; } } return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen); } }
参考: