lotus

贵有恒何必三更眠五更起 最无益只怕一日曝十日寒

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1. 题目

 

题目

 https://leetcode.cn/problems/minimum-window-substring/

这道题目是要求给定两个字符串s和t,找出s中包含t中所有字符的最小子串,如果不存在这样的子串,就返回空字符串。

例如,输入s = "ADOBECODEBANC", t = "ABC",输出"BANC"。¹²

这道题目的难度是Hard,需要用到滑动窗口和哈希表的技巧

 

考查点

这道题考查的是滑动窗口的技巧,以及如何用哈希表来记录和判断字符的出现情况。

  • 滑动窗口是一种常用的处理字符串或数组的方法,可以有效地减少重复的计算和遍历。
  • 哈希表是一种常用的数据结构,可以快速地查找和更新键值对。
  • 2. 解法

 

解题思路

这个问题的关键是找到一个包含 t 中所有字符的最小子串,也就是说,这个子串中每个字符的出现次数要大于等于 t 中对应字符的出现次数。为了做到这一点,我们可以用一个哈希表来记录 t 中每个字符的出现次数,然后用两个指针 left 和 right 来维护一个滑动窗口,表示当前考虑的子串。初始时,left 和 right 都指向 s 的第一个字符。

我们从右边开始扩展窗口,每次移动 right 指针,如果 right 指向的字符在 t 中出现过,就把哈希表中对应的值减一。如果减一后的值等于零,说明我们已经找到了 t 中的一个字符,并且出现次数刚好满足要求。为了记录这种情况,我们用一个变量 count 来表示 t 中不同字符的个数,每次找到一个字符就把 count 减一。当 count 等于零时,说明我们找到了一个包含 t 中所有字符的子串。

接下来,我们要尝试缩小窗口,从左边开始移动 left 指针,如果 left 指向的字符在 t 中出现过,就把哈希表中对应的值加一。如果加一后的值大于零,说明我们失去了 t 中的一个字符,并且出现次数不再满足要求。为了记录这种情况,我们把 count 加一。当 count 大于零时,说明我们需要继续扩展窗口。

在这个过程中,我们每次找到一个有效的窗口时,就更新最小长度和起始位置。最后,我们返回最小长度对应的子串或者空字符串。

 

好的,我可以用以下的步骤来总结我的思路:

  1. 创建一个哈希表 map,记录 t 中每个字符的出现次数。
  2. 初始化两个指针 left 和 right,都指向 s 的第一个字符,表示当前的窗口。
  3. 初始化一个变量 count,表示 t 中不同字符的个数。
  4. 循环以下步骤,直到 right 到达 s 的末尾:
    • 如果 right 指向的字符在 map 中存在,就把 map 中对应的值减一。如果减一后的值等于零,就把 count 减一。
    • 移动 right 指针,扩展窗口。
    • 如果 count 等于零,说明当前的窗口包含了 t 中所有字符,进入以下步骤:
      • 如果当前的窗口长度小于之前记录的最小长度,就更新最小长度和起始位置。
      • 如果 left 指向的字符在 map 中存在,就把 map 中对应的值加一。如果加一后的值大于零,就把 count 加一。
      • 移动 left 指针,缩小窗口。
  5. 返回最小长度对应的子串或者空字符串。

 

具体实现

class Solution {
    public String minWindow(String s, String t) {
        // Use a map to store the frequency of each character in t
        Map<Character, Integer> map = new HashMap<>();
        for (char c : t.toCharArray()) {
            map.put(c, map.getOrDefault(c, 0) + 1);
        }
        
        // Use two pointers to maintain a sliding window
        int left = 0;
        int right = 0;
        int count = map.size(); // The number of distinct characters in t
        int minLen = Integer.MAX_VALUE; // The minimum length of the window
        int start = 0; // The start index of the window
        
        while (right < s.length()) {
            char c = s.charAt(right);
            // If c is in t, decrease its frequency by one
            if (map.containsKey(c)) {
                map.put(c, map.get(c) - 1);
                // If c's frequency becomes zero, decrease the count by one
                if (map.get(c) == 0) {
                    count--;
                }
            }
            
            // Move the right pointer forward
            right++;
            
            // When the count is zero, we have found a valid window
            while (count == 0) {
                // Update the minimum length and start index if needed
                if (right - left < minLen) {
                    minLen = right - left;
                    start = left;
                }
                
                char d = s.charAt(left);
                // If d is in t, increase its frequency by one
                if (map.containsKey(d)) {
                    map.put(d, map.get(d) + 1);
                    // If d's frequency becomes positive, increase the count by one
                    if (map.get(d) > 0) {
                        count++;
                    }
                }
                
                // Move the left pointer forward
                left++;
            }
        }
        
        // Return the substring or empty string
        return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
    }
}

  

3. 总结

 

posted on 2023-04-28 20:52  白露~  阅读(8)  评论(0编辑  收藏  举报