76.最小覆盖字字串(使用到collection.defaultdict)

最小覆盖字串

方式一:滑动窗口

思路:使用两个指针,不断使得窗口扩大,然后找出包含所有的子串的子串。

有几个很重要的变量:need,needCnt,i,j
新建字典need的作用(两个地方使用):
1.这里主要在排查是否完全出现了t中的元素的时候:通过int整数的增减来统计元素的个数,若遍历到含有t的元素,新建的len()减一,直到len()为零,则算是包含了全部,并且t所含的元素个数置零
2.判断是否是最小子串,排查前边的元素的时候
3.其中need[c]的减一加一是一个很重要的点。

from collections import defaultdict
def minWindow(s: str, t: str):
    # 创建need[c],通过字典统计t中的元素出现的次数。
    need = defaultdict(int)
    for c in t:
        need[c]+=1
    needCnt=len(t)
    i=0#首指针
    res=(0,float('inf'))

    #两个循环嵌套,第一个j用来移动尾指针j的位置,第二个while用来移动首指针i的位置
    for j,c in enumerate(s):
        if need[c]>0:#若是在s当中出现t中的元素
            needCnt-=1#zeneedCnt-1,用于统计是否覆盖最小子串的全部内容。
        need[c]-=1#无论是否是t中出现的元素,都减一,而一开始的时候t中元素已经是1,所以减一之后是0,不是t中的元素则是-1,新建字典need中元素个数减一
        if needCnt==0:       #步骤一:滑动窗口包含了所有T元素
            while True:      #步骤二:增加i,排除多余元素(排除的是前边的元素,后边元素的结点已经确定了)
                c=s[i]#第一遍循环是从s[0]开始的,从s[0]开始排查直到出现t中包含的元素为止。
                print(need[c])
                h = need[c]
                if need[c]==0:
                    break#当前结束之后,i指针指向的是s中出现的第一个字母,j指针指向的是t出现的最后一个字母。
                need[c]+=1#??这一步的作用是什么
                i+=1
            #这也是一个挺牛皮的点,因为要用小于号,所以这里创建的是从零到正无穷的变量
            if j-i<res[1]-res[0]:   #记录结果
                res=(i,j)#记录位置
                g = s[res[0]:res[1]+1]
                print(g)

            #下边这一步很重要:i+1相当于网签移动一个位置,这时候整子串减少的就是最前边的元素,所以要让最前边的元素的need加一,并且needCnt加一,
            #下一个循环中,还是一样,遇到need>0时候,needCnt减一,判断为已经包含全部字符,进入下一个循环。'''
            need[s[i]]+=1  #步骤三:i增加一个位置,寻找新的满足条件滑动窗口
            needCnt+=1
            i+=1
    return '' if res[1]>len(s) else s[res[0]:res[1]+1]    #如果res始终没被更新过,代表无满足条件的结果

a = minWindow('ADOBECODEBANC','ABC')
print(a)

方式二:暴力遍历

lass Solution:
    def minWindow(self, s, t):
        need_dict = collections.defaultdict(int) #用来装分别需要的字符数量,包括必要的和非必要的,需要的必要字符数量>0,非必要的字符数量<0
        for ch in t:   #初始化需要的必要字符数量
            need_dict[ch] += 1
        need_cnt = len(t) #用来判断总共需要多少字符才能达到要求
        i = j = 0
        res = [0,float('inf')]
        for j in range(len(s)):
            if need_dict[s[j]] > 0: #只有必要字符的数量才可能>0
                need_cnt -= 1
            need_dict[s[j]] -= 1  #任意值都可以装进need_dict,但是非必要字符只可能<0
            if need_cnt == 0:  # 需要的字符都足够了
                while need_cnt == 0: #开始准备右移左指针,缩短距离
                    if j-i < res[1] - res[0]: #字符串更短,替换答案
                        res = [i,j]
                    need_dict[s[i]] += 1    #在移动左指针之前先将左指针的值加回来,这里可以是非必要字符
                    if s[i] in t and need_dict[s[i]] > 0: #确认是必要字符且不多于所需要的数量(有多余的话只可能<=0,因为上一句我们已经将字符+1了)后,将need_cnt+1
                        need_cnt += 1
                    i += 1   #右移左指针,寻找下一个符合的子串
        return s[res[0]:res[1]+1] if res[1]-res[0]<len(s) else ''

补充知识:collection.defaultdict

作用:在collection.default()中,如果是list,则可以对键进行归类,通过sort进行排序,如果是int,可以进行键个数的加减。

python中通过key访问字典,当Key不存在的时候,会引发KeyError异常,为了避免这种状况发生,可以使用collections类当中的defaultdict()方法来为字典提供默认值。

  • 1.使用list作为第一个参数,可以很容易将键-值对序列转换为列表字典。
from collections import defaultdict

s = [('yellow',1),('blue',2),('yellow',3),('blue',4),('red',5)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)
a = sorted(d.items())
print(d)
print(a)

dict.setdefault()也有同样的效果,但是这个更为便捷

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d={}
for k, v in s:
  d.setdefault(k,[]).append(v)
print(d)
a=sorted(d.items())
print(a)
  • 2.defaultdict还可以用来计数,将default_factory设置为int
    #字符串中的字母第一次出现的时候,字典中没有非字母,default_factory函数调用int()为其提供一个默认值0
s = 'mississippi'
d = defaultdict(int)
for k in s:
    print(k)
    d[k] += 1#这种方式可以直接字典d中的值
print(d)
a=sorted(d.items())
print(a)
  • 3.函数int()是常值函数的一种特例,总是返回0,使用匿名函数lambda function可以更快、更灵活的创建常值函数,返回包括0在内的任意常数值
def constant_factory(value):
    return lambda:value
d = defaultdict(constant_factory('<missing>'))
print(d)
d.update(name = 'John', action = 'ran')
print(d)
print('%(name)s%(action)s to %(object)s%d')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liqianjiqiren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值