LeetCode解题记录 —— LeetCode76 Minimum Window Substring

题目:给定字符串s和t,要求求出s中包含t的所有字符(包括字符种类和数量)的最短子串

示例:
Example 1:
Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"

Example 2:
Input: s = "a", t = "a"
Output: "a"

通过滑动窗口法(sliding-window)求解。定义变量left和right,match,定义数组map。其中left和right为s的子串的左右边界,left,right初始化为0。start为满足条件的最短子串的起始位置。len为满足条件的最短子串的长度。match表示子串s[left .. right]中还差多少个字符可以包含t的所有字符,match初始化为t的长度,当match == 0时表示子串s[left .. right]包含了t的所有字符。map初始化为t中每个字符出现的次数。

int left = 0;
int right = 0;
int start = -1;
int len = s.length() + 1;
int match = t.length();
int[] map = new int[128];

以 s = "acbba", t = "abb"说明,首先初始化left = 0, right = 0, len = s.length() + 1 = 6, match = t.length() = 3, 初始化map,map['a'] = 1, map['b'] = 2, 其余都为0。

  1. left == 0, right == 0,s[0] == 'a'。令map['a']--, 此时map['a'] == 0, 表示之前map['a'] > 0, 说明'a'在t中,此时s[left .. right]即s[0]包含了t的一个字符,所以令match--, 执行完以后match为2,令right++, 最后left == 0, right == 1, match == 2

  2. left == 0, right == 1, s[1] == 'c', 令map['c']--, 此时map['c'] == -1, 表示之前map['c'] == 0, 说明'c'不在t中,match不用变化,令right++, 最后left == 0, right == 2, match == 2

  3. left == 0, right == 2, s[2] == 'b', 令map['b']--, 此时map['b'] == 1, 表示之前map['b'] > 0, 说明'b'在t中,此时s[left .. right]即s[0 .. 2]又包含了t的一个字符,所以令match--, 此时match == 1, 令right++, 最后left == 0, right == 3, match == 1

  4. left == 0, right == 3, s[3] == 'b', 令map['b']--, 此时map['b'] == 0, 表示之前map['b'] > 0, 说明'b'在t中,此时s[left .. right]即s[0 .. 3]又包含了t的一个字符,所以令match--, 此时match == 0, 说明子串s[0 .. 3]包含了t中的所有字符。此时可以通过left向右移动将满足条件的s[left .. right]缩短吗,此时left == 0,s[0] == 'a',map['a'] == 0, 如果令left++,则子串s[1, 3]会少一个字符'a',不满足条件。所以此时满足条件的最短子串就是s[0 .. 3],right- left + 1 = 3 - 0 + 1 = 4 < len == 6,此时更新最短子串长度len = 4, 起始位置为start = 0,令right++, 最后left == 0, right == 4,match == 0

  5. left == 0, right == 4, s[4] == 'a', 令map['a']--, 此时map['a'] == -1, 表示s[0 .. 4]中多包含了一个'a', 此时match不用变化。match == 0,此时如果将left向右移动可以得到更短的子串吗,left == 0, s[0] == 'a', map['a'] == -1, 此时s[0 .. 4]中已经多包含了一个'a', 将这个'a'去掉后的子串s[1..4]仍然满足条件,因此令left++。此时left == 1, s[1] == 'c', map['c'] == -1, 说明s[1 .. 4]中多包含了一个'c',将这个'c'去掉后的子串s[2 .. 4]仍然满足条件,因此令left++。此时left == 2, s[2] == 'b', map['b'] == 0, 说明s[2 .. 4]中恰好包含了t中'b'的数量的'b', 因此这个'b'不能去掉,此时left == 2, right == 4, right - left + 1 = 3 < len == 4, 此时更新len = 4, start = 2。更新完之后令map[s[left]]++, left++, match++, 最后令right++, left == 3, right == 5, match == 1,

  6. right == 5 == s.length(),过程结束

public String minWindow(String s, String t) { if (s == null || t == null) { return ""; } int[] map = new int[128]; int left = 0; int right = 0; int start = -1; int len = s.length() + 1; int match = t.length(); for (int i = 0; i < t.length(); i++) { map[t.charAt(i)]++; } while (right < s.length()) { map[s.charAt(right)]--; if (map[s.charAt(right)] >= 0) { match--; } if (match == 0) { while (map[s.charAt(left)] < 0) { map[s.charAt(left)]++; left++; } if (right - left + 1 < len) { start = left; len = right - left + 1; } map[s.charAt(left)]++; left++; match++; } right++; } return start == -1 ? "" : s.substring(start, start + len); }

posted @ 2020-12-08 23:33  wflying  阅读(72)  评论(0)    收藏  举报