替换子串得到平衡字符串[map计数+滑动窗口]

前言

对于子串问题,确定左边界和有边界,就能确定一个子串,暴力取子串,时间复杂度O(n2)。有时挖掘内在规律的限定,或者问题所限定,就可以采用滑动窗口寻找子串,时间复杂度O(n)。

一、替换子串得到平衡字符串

在这里插入图片描述

二、map计数+滑动窗口

// 目的:待替换子串的最小可能长度
// 这个子串里应该包含超过len(s) >> 2的字符串的多余个数。
// 确定一个最小窗口,使得外面的每种字符都小于n/4即可(更简单的逆向判断)。
// 滑动窗口

func balancedString(s string) int {
    // 初始化每个字符对应的数组下标,便于统计。
    fx := map[byte]int{'Q':0,'W':1,'E':2,'R':3}
    // 记录每个字符出现的次数
    cnt := [4]int{}
    for i := 0;i < len(s);i++ {
        cnt[fx[s[i]]]++
    }
    
    n := len(s) >> 2
    // 已经平衡
    if isOk(cnt,n) {
        return 0
    }
    // 滑窗记录最小替换子串
    left,right,m := 0,0,len(s)
    for ;right < len(s);right++ {
        cnt[fx[s[right]]]--
        if !isOk(cnt,n) {
            continue
        }
        // 一旦圈住了多余的字符,就移动左边界,寻找最短多余子串。
        for ;left <= right && isOk(cnt,n);left++ {
            cnt[fx[s[left]]]++ 
        }
        // 记录最短可替换多余子串。
        m = min(m,right - left + 2)
    }
    return m
}
// 窗口外的每类字符数是否都不超过n
func isOk(cnt [4]int,n int) bool {
    for _,v := range cnt {
        if v > n {
            return false
        }
    } 
    return true
}
func min(x,y int) int {
    if x < y {
        return x
    }
    return y
}

总结

1)问题转换,通过对字符的计数,以及计数的修改,来判断字符内外的情况。
2)逆向判定,通过窗口外的字符情况,来判断窗口内是否包含了所有多余字符,再左边界右滑,把可替换子串压缩到最小。
3)选择的可能性很多,我们需要挖掘其中规律及限定,来计算有效的可能性。例如O(n)的滑窗就oK了,而不是O(n方)来确定子串是否有效。

参考文献

[1] LeetCode 替换子串得到平衡字符串

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值