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

1、题目

LeetCode 打卡 Day 40 —— 最小覆盖子串_第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; i0; 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])
}

提交结果如下

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

你可能感兴趣的:(Go,LeetCode,leetcode)