zoukankan      html  css  js  c++  java
  • [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
        }
    }
    
  • 相关阅读:
    Tomcat环境的搭建(web基础学习笔记一)
    子查询二(在HAVING子句中使用子查询)
    子查询一(WHERE中的子查询)
    分组统计查询(学习笔记)
    Oracle体系结构一(学习笔记)
    表分区(学习笔记)
    索引(学习笔记)
    序列(学习笔记)
    触发器七(复合触发器)(学习笔记)
    触发器六(系统触发器)(学习笔记)
  • 原文地址:https://www.cnblogs.com/zhongju/p/14182901.html
Copyright © 2011-2022 走看看