Java实现查找最短匹配字符串(LeetCode最短窗口子字符串)

版权声明:转载请标明出处 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

核心思想: 首尾双指针,尾指针右移扩张找到包含目标字符的子串,首指针右移收缩使字串最小。

做法:

  1. 创建一个数组或者集合(map就很合适),存储T中对应的字符个数
  2. 遍历源字符串s,遇到 t 中字符c,将该字符c转换为数组中的索引c0,并且arr[c0]-1,或设置为map中的key,其Value减一,直到当前子串包含了所有 t 中的字符,记录该子串,并更新最小子串。
  3. 收缩该子串,首指针右移 忽略不在 t 中的字符。 当 子串中出现某字符次数多于 t 中该字符的个数,也可忽略该字符。比如 找到某子串 AACD ,t = ACD,则第一个A也可忽略。 直到右移至 该子串缺失某字符。如 ACD CD
  4. 重复2 3,直到遍历到s尾

解释一下:

  1. char类型有两个字节,即大小可以为0-255,所以可以创建数组dp=int[255]来存储T中的对应字符个数,比如 dp[‘a’]=dp[97]=a在T中的个数。如果要匹配的只是字母,也可以只创建dp[26]其他字符不存入,如果是b,就dp[b-‘a’] 不就把a-z转换成1-26了嘛。
  2. 遍历T中的字符存入dp,如果dp[index]>0,则表示index对应的字符属于T中匹配所需要的字符,
for(int i=0;i<tLow.length();i++) {
			dp[tLow.charAt(i)]++;  //记录每个要匹配字符的个数
}
  1. 用窗口去匹配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);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_40661297/article/details/89549427