- 只关心字符是否出现,并不关心字符出现的次数。
滑动窗口的定义:表示滑动窗口内部包含了
t
中的字符个数,这里借用了编辑距离的概念。
方法一:定义距离
Java 代码:
public class Solution {
public String minWindow(String s, String t) {
int[] window = new int[128];
int[] pattern = new int[128];
final int A = 'A';
char[] tCharArray = t.toCharArray();
for (Character c : tCharArray) {
pattern[c - A]++;
}
// 表示滑动窗口内部包含了 t 中的字符个数,这里借用了编辑距离的概念
int distance = 0;
for (int i = 0; i < 128; i++) {
if (pattern[i] > 0) {
distance++;
}
}
int sLen = s.length();
int start = 0;
int left = 0;
int right = 0;
int match = 0;
int minLen = sLen + 1;
char[] sCharArray = s.toCharArray();
// 滑动窗口定义:[left, right) 是包含 T 的子串
while (right < sLen) {
Character curChar = sCharArray[right];
if (pattern[curChar - A] > 0) {
window[curChar - A]++;
if (window[curChar - A] == pattern[curChar - A]) {
match++;
}
}
right++;
while (match == distance) {
if (right - left < minLen) {
start = left;
minLen = right - left;
}
// 考虑左边界向右边走
Character leftChar = sCharArray[left];
if (pattern[leftChar - A] > 0) {
window[leftChar - A]--;
if (window[leftChar - A] < pattern[leftChar - A]) {
match--;
}
}
left++;
}
}
if (minLen == sLen + 1) {
return "";
}
return s.substring(start, start + minLen);
}
public static void main(String[] args) {
Solution solution = new Solution();
String S = "ADOBECODEBANC";
String T = "ABC";
String minWindow = solution.minWindow(S, T);
System.out.println(minWindow);
}
}
方法二:定义字符数是否一样
滑动窗口方法是暴力解法的优化,窗口在滑动的过程中,不会错过最优解。
- 右边界可以前进的条件:还没有包含
T
的所有字母; - 左边界可以前进的条件:已经包含了
T
的所有字母; - 滑动窗口定义:
[left, right)
内包含了T
的所有字母,长度为right - left
。
Java 代码:
public class Solution {
/**
* 首先建立文本串和模式串的概念
*
* @param s 文本串
* @param t 模式串
* @return
*/
public String minWindow(String s, String t) {
int[] pattern = new int[128];
int[] window = new int[128];
for (char ct : t.toCharArray()) {
pattern[ct]++;
}
// t 中有多少种字符,重复字符只记录一次
int tCount = 0;
// 滑动窗口内有多少种字符在 t 中
int sCount = 0;
// 首先计算滑动窗口内的元素和 pattern 的差距
for (int i = 0; i < 128; i++) {
if (pattern[i] > 0) {
tCount++;
}
}
int sLen = s.length();
int start = 0;
int left = 0;
int right = 0;
int minLen = sLen + 1;
char[] sCharArray = s.toCharArray();
while (right < sLen) {
if (pattern[sCharArray[right]] > 0) {
window[sCharArray[right]]++;
if (window[sCharArray[right]] == pattern[sCharArray[right]]) {
sCount++;
}
}
right++;
while (sCount == tCount) {
// 想清楚为什么在这里取最小值,此时 [left, right) 内正好包含 T 的所有字母,这一段要写在 left 移动之前
if (right - left < minLen) {
minLen = right - left;
start = left;
}
if (pattern[s.charAt(left)] > 0) {
window[s.charAt(left)]--;
if (window[s.charAt(left)] < pattern[s.charAt(left)]) {
sCount--;
}
}
left++;
}
}
if (minLen == sLen + 1) {
return "";
}
return s.substring(start, start + minLen);
}
}