最小窗口子字符串
给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
分析:
分析思路参考:https://blog.csdn.net/whdAlive/article/details/81132383
核心思想: 首尾双指针,尾指针右移扩张找到包含目标字符的子串,首指针右移收缩使字串最小。
做法:
- 创建一个数组或者集合(map就很合适),存储T中对应的字符个数
- 遍历源字符串s,遇到 t 中字符c,将该字符c转换为数组中的索引c0,并且arr[c0]-1,或设置为map中的key,其Value减一,直到当前子串包含了所有 t 中的字符,记录该子串,并更新最小子串。
- 收缩该子串,首指针右移 忽略不在 t 中的字符。 当 子串中出现某字符次数多于 t 中该字符的个数,也可忽略该字符。比如 找到某子串 AACD ,t = ACD,则第一个A也可忽略。 直到右移至 该子串缺失某字符。如 ACD CD
- 重复2 3,直到遍历到s尾
解释一下:
- char类型有两个字节,即大小可以为0-255,所以可以创建数组dp=int[255]来存储T中的对应字符个数,比如 dp[‘a’]=dp[97]=a在T中的个数。如果要匹配的只是字母,也可以只创建dp[26]其他字符不存入,如果是b,就dp[b-‘a’] 不就把a-z转换成1-26了嘛。
- 遍历T中的字符存入dp,如果dp[index]>0,则表示index对应的字符属于T中匹配所需要的字符,
for(int i=0;i<tLow.length();i++) {
dp[tLow.charAt(i)]++; //记录每个要匹配字符的个数
}
- 用窗口去匹配S,开始begin=end = 0,先让end右移,当dp[end]>0时,表示这个字符是T中的字符,此时count++(count表示匹配到的字符数),执行dp[c-‘a’]-1;表示在这个窗口中包含了这个字符,所需字符数要减一。
。。。。。算了,不写了,相信你,直接看代码吧,写了三个实现方法,两个用数组的,一个用map的
public class ShortestMatchedString {
public static void main(String[] args) {
String s = "ADOBECODEBANC";
String t = "Abc";
System.out.println('a'-0);
String shortestSubString1 = findShortestSubString1(s, t);
String shortestSubString2 = findShortestSubString2(s, t);
String shortestSubString3 = findShortestSubString3(s, t);
System.out.println(shortestSubString1);
System.out.println(shortestSubString2);
System.out.println(shortestSubString3);
}
/**方法一
* 该方法适用于所有字符
* @param s
* @param t
* @return
*/
private static String findShortestSubString1(String s, String t) {
String tLow = t.toLowerCase();
String sLow = s