leetcode76. 最小覆盖子串

解题思路:滑动窗口
用一个左右可移动的双指针寻找符合条件的一段字符串

  1. 具体做法是初始时双指针都指向零,用两个字典记录need需要寻找的字符串的每个字符及其个数和win已经找到的字符串的字符及个数用一个vaild数组记录已经满足要求的元素的个数
  2. 之后移动r指针直到其满足要求即字符串的元素和个数都满足寻找的要求即win满足need
  3. 之后尝试移动指针缩小区间直到其不满足条件,即字符串的元素和个数不满足寻找的要求,这时我们需要记录上次的答案防止后面已经没有满足要求的
  4. 重复2,3步骤,不断更新最小区间,直到r指针出界。
def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        need = collections.Counter(t)  #记录需要的元素及个数
        win = dict()                   #记录找到的元素及个数
        l,r = 0,0                      #指针都指向0
        min_len = len(s)+1             #记录最小长度
        vaild = 0                      #记录满足的个数
        for r in range(len(s)):
            if s[r] in need:           #这个r满足条件,这里别判断是否在字符串中,时间复杂度会大幅提升
                win[s[r]] = win.get(s[r], 0) + 1  #更新win字典
                if win[s[r]] == need[s[r]]:       #这个元素刚好满足要求了
                    vaild += 1                    #满足的个数加一
            while vaild == len(need):             #都满足之后尝试缩小
                if r-l+1 < min_len:               #先更新最小长度
                    min_len = r-l+1
                    start = l
                if s[l] in win:                   #注意这里判断是否在字典中,别判断是否在字符串中,时间复杂度会大幅提升
                    if win[s[l]] == need[s[l]]:    #如果这个元素不满足了(注意这里使用==之后再更新,不能用<,因为重复的会减小几次)
                        vaild -= 1                #满足的个数减一
                    win[s[l]] -= 1                #更新win
                l += 1
        if min_len == len(s) + 1:
            return ""
        return s[start:start+min_len]

另一种写法

def minWindow(self, s: str, t: str) -> str:
        
        if len(t) > len(s):
            return ''        
        
        cnt = collections.Counter(t)    # 哈希表:记录需要匹配到的各个元素的数目
        need = len(t)                   # 记录需要匹配到的字符总数【need=0表示匹配到了】
        
        n = len(s)
        start, end = 0, -1          # 记录目标子串s[start, end]的起始和结尾
        min_len = n + 1             # 符合题意的最短子串长度【初始化为一个不可能的较大值】
        left = right = 0            # 滑动窗口的左右边界
        
        for right in range(n):
            
            # 窗口右边界右移一位
            ch = s[right]               # 窗口中新加入的字符
            if ch in cnt:               # 新加入的字符位于t中
                if cnt[ch] > 0:         # 对当前字符ch还有需求
                    need -= 1           # 此时新加入窗口中的ch对need有影响
                cnt[ch] -= 1
            
            # 窗口左边界持续右移
            while need == 0:            # need=0,当前窗口完全覆盖了t
                if right - left + 1 < min_len:      # 出现了更短的子串
                    min_len = right - left + 1
                    start, end = left, right
                
                ch = s[left]            # 窗口中要滑出的字符
                if ch in cnt:           # 刚滑出的字符位于t中
                    if cnt[ch] >= 0:    # 对当前字符ch还有需求,或刚好无需求(其实此时只有=0的情况)
                        need += 1       # 此时滑出窗口的ch会对need有影响
                    cnt[ch] += 1
                left += 1               # 窗口左边界+1
        
        return s[start: end+1]

你可能感兴趣的:(数组,滑动窗口,算法,python)