版权声明:转载请标明出处 https://blog.csdn.net/weixin_40661297/article/details/89549427
最小窗口子字符串
给定一个字符串 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.toLowerCase();
int[] dp = new int[257];
for(int i=0;i<tLow.length();i++) {
dp[tLow.charAt(i)]++;
}
int begin=0,end = 0;
int minBegin = 0;
int minLength = Integer.MAX_VALUE;
int count = 0;
while(end<sLow.length()) {
if(dp[sLow.charAt(end)]>0) {
count++; // 如示例,只有匹配到第一个a时count才会加1,之后的dp[a]<=0,即不再是匹配T所必需的字符了(以为已经有一个了)
}
dp[sLow.charAt(end)]--; //窗口中的每个字符都要减一
end++;
while(count==t.length()) {
if(end-begin<minLength) {
minLength = end - begin;
minBegin = begin;
}
if(dp[sLow.charAt(begin)]==0) {
count--;
}
dp[sLow.charAt(begin)]++;
begin++;
}
}
if(minLength!=Integer.MAX_VALUE) {
String shortestString = s.substring(minBegin,minBegin+minLength);
return(shortestString);
}else {
return ("没找到唉");
}
}
/**方法二
*此方法仅适用于匹配字符都是字母的情况
* @param s
* @param t
* @return
*/
private static String findShortestSubString2(String s,String t) {
String sLow = s.toLowerCase();
String tLow = t.toLowerCase();
int[] dp = new int[26];
for(int i=0;i<tLow.length();i++) {
dp[tLow.charAt(i)-'a']++;
}
int begin = 0,end = 0;
int minLength = Integer.MAX_VALUE;
int minBegin = 0;
int count = 0;
while(end<sLow.length()) {
char c = sLow.charAt(end);
if('a'<=c&&c<='z') {
if(dp[c-'a']>0) {
count++;
}
dp[c-'a']--;
}
end++;
while(count==tLow.length()) {
if(end-begin<minLength) {
minBegin = begin;
minLength = end-begin;
}
char m = sLow.charAt(begin);
if('a'<=m&&'z'>=m) {
if(dp[m-'a']==0) {
count--;
}
dp[m-'a']++;
}
begin++;
}
}
if(minLength==Integer.MAX_VALUE) {
return "没找到唉";
}else{
return s.substring(minBegin,minBegin+minLength);
}
}
/**方法三
* 用map存值
* 可以匹配任何元素
* @param s
* @param t
* @return
*/
private static String findShortestSubString3(String s,String t) {
String sLow = s.toLowerCase();
String tLow = t.toLowerCase();
HashMap<Character, Integer> map = new HashMap<>();
for(char c:tLow.toCharArray()) {
if(map.containsKey(c)) {
map.put(c, map.get(c)+1);
}else {
map.put(c, 1);
}
}
int begin=0,end = 0;
int count = 0;
int minBegin = 0;
int minLength = Integer.MAX_VALUE;
while(end<sLow.length()) {
char c = sLow.charAt(end);
if(map.containsKey(c)) {
if(map.get(c)>0) {
count++;
}
map.put(c,map.get(c)-1);
}
end++;
while(count==tLow.length()) {
if(end-begin<minLength) {
minBegin = begin;
minLength = end-begin;
}
char m = sLow.charAt(begin);
if(map.containsKey(m)) {
if(map.get(m)==0) {
count--;
}
map.put(m,map.get(m)+1);
}
begin++;
}
}
if(minLength==Integer.MAX_VALUE) {
return "没找到唉";
}else{
return s.substring(minBegin,minBegin+minLength);
}
}
}