• [LeetCode] 76. Minimum Window Substring(最小窗口子串)


    Description

    Given two strings s and t, return the minimum window in s which will contain all the characters in t. If there is no such window in s that covers all characters in t, return the empty string "".
    给定两字符串 st,返回 s 的一个最小窗口(子串),该子串包含 t 中所有字符。如果找不到这样的窗口(子串),则返回空串 ""

    Note that If there is such a window, it is guaranteed that there will always be only one unique minimum window in s.
    注意,如果存在这样的窗口(子串),输入保证该窗口(子串)唯一。

    Examples

    Example 1

    Input: s = "ADOBECODEBANC", t = "ABC"
    Output: "BANC"
    

    Example 2

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

    Constraints

    • 1 <= s.length, t.length <= 1e5
    • s and t consist of English letters.

    Follow up

    Could you find an algorithm that runs in O(n) time?

    Hints

    1. Use two pointers to create a window of letters in S, which would have all the characters from T.

    2. Since you have to find the minimum window in S which has all the characters from T, you need to expand and contract the window using the two pointers and keep checking the window for all the characters. This approach is also called Sliding Window Approach.

      L ------------------------ R , Suppose this is the window that contains all characters of T
      
              L----------------- R , this is the contracted window. We found a smaller window that still contains all the characters in **T**
      

      When the window is no longer valid, start expanding again using the right pointer.

    Solution

    子串问题优先考虑滑动窗口。首先需要统计 t 中字母出现的次数。然后扩展窗口右边界,寻找能包含 t 中所有字母的窗口,再扩展窗口左边界,去掉“不必要的字母”。代码如下:

    class Solution {
        fun minWindow(s: String, t: String): String {
            if (s.length < t.length) {
                return ""
            }
            val countMap = hashMapOf<Char, Int>()
            t.forEach { countMap[it] = (countMap[it] ?: 0) + 1 }
    
            var left = 0
            // 统计窗口内匹配到了 t 中的多少字母
            var match = 0
            var minLength = Int.MAX_VALUE
            var result = ""
    
            for (right in s.indices) {
                // 为什么直接在原 map 上改?
                // 这是为了方便统计,直接在 map 上改,那么判断“窗口恰好包含 t 中所有字母”的条件是
                // map 里所有 t 包含的字母,对应的频率为 0
                // 对于 t 不包含的字母,其对应的 value 永远小于 0
                countMap[s[right]] = (countMap[s[right]] ?: 0) - 1
                if (countMap.getValue(s[right]) >= 0) {
                    match++
                }
                while (match == t.length) {
                    if (minLength > right - left + 1) {
                        minLength = right - left + 1
                        result = s.substring(left..right)
                    }
                    countMap[s[left]] = (countMap[s[left]] ?: 0) + 1
                    if (countMap.getValue(s[left]) > 0) {
                        // 窗口收缩导致 t 中有一个字母没包括进去
                        match--
                    }
                    left++
                }
            }
            return result
        }
    }
    
  • 相关阅读:
    Difference (第k大(二分)+双指针+ST表)+(很多小细节!!!!!) (MINIEYE杯十六届)
    electronvue实现自定义区域拖拽窗口
    PHP 发送短信
    C#VS2017快捷操作(查看方法重载)
    bootstrapdatetimepicker源代码分析
    Linux下的dstat命令详解以及部分参数说明
    《金字塔原理》
    三年职业生涯回顾
    C++_02_类型转换
    C++_03_动态内存与智能指针
  • 原文地址:https://www.cnblogs.com/zhongju/p/14182901.html
Copyright © 2020-2023  润新知