LeetCode 打卡 Day 40 —— 最小覆盖子串

45 篇文章 0 订阅

1、题目

2、题解

困难级别的问题,不出意外把我困难住了😭,纠结了半天能否用动态规划进行解决,没想到动态规划的具体解决办法,所以还是直接去看题解了。题解使用了滑动窗口,印象中这是第一次看到滑动窗口算法,之前只在计算机网络中接触过。具体的算法内容如下:

假设窗口的左右边界分别为 leftW 和 rightW

1)首先固定 leftW ,不断前移增加 rightW,直到窗口内的字符串满足要求。

2)之后固定 rightW,不断前移left,去除无用字符,直指满足要求的最小窗口,记录此时窗口长度与位置。

3)前移 leftW 后,再次将其固定,重复1)和 2),直指窗口滑动至字符串末尾。

所面临的问题

1)如何判断窗口包含所有字符

解:运用字典类型,针对子串中的每一个字符存储所需要的个数,每次滑动到一个字符,对应字符--,<=0 时表明该字符已被窗口包含。

优化:每次都需要对创建的字典类型进行遍历,以判断字符串是否满足要求,浪费时间。

思路:用一个整数 flag 代表字典的长度,每当一个字典元素<=0,整数-1;>0 时整数加1,整数为0时表明窗口包含全部字符。

2)想要优化的话,如何忽略多余判断的字符(题解中的优化问题),比如 [XXXXABC],子串是ABC,如何省略判断前面的多个 XXXX

判断 leftW 对应的字符是否是子串的字符,移动 leftW 直至是子串字符,再对其固定移动rightW。

实现代码如下:

func minWindow(s string, t string) string {
    left, right := 0, 0
    min := math.MaxInt32
    l := len(s)

    substrMap := make(map[byte]int)
    for i:=0; i<len(t); i++{
        substrMap[t[i]]++
    }
    flag := len(substrMap)

    for leftW, rightW:=0, 0; leftW<l; leftW++{
        vl:=s[leftW]
        if _, ok := substrMap[vl]; ok{// 发现左窗口边界
            if rightW<leftW{
                rightW=leftW
            }
            for ;rightW<l&&flag>0; rightW++{
                vr:=s[rightW]
                if _, ok := substrMap[vr]; ok{
                    substrMap[vr]--
                    if substrMap[vr]==0{
                        flag--
                    }
                }else{
                    continue
                }
            }
        }else{
            continue
        }
        if flag==0{   // 构成一个窗口,记录长短
            // fmt.Println(leftW, rightW)
            if min>rightW-leftW+1{
                left,right=leftW,rightW
                min=rightW-leftW+1
            }
            substrMap[vl]++
            if substrMap[vl]>0{
                flag++
            }
        }
    }
    return string(s[left:right])
}

提交结果如下

 与题解的运行结果相比,时间与内存均降低了(第一个是题解的提交结果,第二个是自己代码的提交结果)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值