子串相关问题

    子串相关的问题直观的解法通常时间复杂度都比较高。如下模板可以借鉴解决很多相关问题:

int findSubstring(string s){
        vector<int> map(128,0);
        int counter; // check whether the substring is valid
        int begin=0, end=0; //two pointers, one point to tail and one  head
        int d; //the length of substring

        for() { /* initialize the hash map here */ }

        while(end<s.size()){

            if(map[s[end++]]-- ?){  /* modify counter here */ }

            while(/* counter condition */){ 
                 
                 /* update d here if finding minimum*/

                //increase begin to make it invalid/valid again
                
                if(map[s[begin++]]++ ?){ /*modify counter here*/ }
            }  

            /* update d here if finding maximum*/
        }
        return d;
  }

    具体实例如下:

    1. 最小子串窗口问题

    给定两个字符串S和T,求在S中包含T中所有字母的最小子串窗口。如S="ADOBECODEBANC",T="ABC",则最小子串窗口为"BANC"。

   def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        #初始化一个dict,把S中所有字符都记录进去,并且设置其值为0
        dict = {c: 0 for c in s}
        #对于T中的每一个字符c,如果dict中不包含c,说明T中有S中不含有的字符,直接返回;否则,把dict[c]的值加1(如果c在T中出现k次,那么dict[c]的值就是k,也就是c需要在S中被匹配k次)
        for c in t:
            if c not in dict:
                return ""
            dict[c] += 1
        #设置计数器counter为T的长度,用于记录需匹配的字符数量
        counter = len(t)
        #设置循环的起点、终点指针,记录子窗口的长度,以及其起点
        begin, end, d, head = 0, 0, 2 ** 30, 0
        #对S进行遍历
        while end < len(s):
            #如果dict[c]值大于0,说明T中含有c,且未被其他前面的字符匹配掉,则匹配成功一个字符,需匹配的字符数counter减1
            if dict[s[end]] > 0:
                counter -= 1
            #把dict[c]的值减1(T中不含有的字符其值都为负数)
            dict[s[end]] -= 1
            end += 1
            #如果counter==0,说明T中所有字符都已经被成功匹配,则开始考虑把窗口的起点进行右移,寻找最优解
            while counter == 0:
                if end - begin < d:
                    head = begin
                    d = end - begin
                #如果dict[c]==0,说明dict[c]是T中的字符,跳过该字符后,窗口就不包含T中所有字符了(当counter为0时,dict中的值要么为负数,要么为0,其中值为0,且在s中遍历过的,只有T中包含的字符)。此时将counter加1,说明又有一个字符需匹配了。
                if dict[s[begin]] == 0:
                    counter += 1
                #将dict[c]值加1,如果是T中含有的字符,那么此时该值应该为正数,说明T中还有dict[c]个c需匹配。如果不是T中的字符,前面遍历S的时候减一次,这里再加一次,肯定还是非正数
                dict[s[begin]] += 1
                begin += 1
        
        return s[head: head + d]

    2. 最多有两个不同字符的最长子串

    给定一个字符串,求其中最多含有两个不同字符的最长子串的长度。如"eceba"的满足要求的子串为"ece","ecebbbbba

def lengthOfLongestSubstringTwoDistinct(self, s):
    dict = {c: 0 for c in s}
    counter = 0
    begin, end, d, head = 0, 0, 0, 0
    while end < len(s):
        if dict[s[end]] == 0:
            counter += 1
        while counter > 2:
            if end - begin > d:
                d = end - begin
                head = begin
            if dict[s[begin]] == 1:
                counter -= 1
            dict[s[begin]] -= 1
            begin += 1

        dict[s[end]] += 1
        end += 1
    return d

    3. 无重复字符的最长子串

    给定一个字符串S,求S中不含重复字符的最长子串的长度。如"abcabcbb"的不含重复字符的子串为"abc"

def lengthOfLongestSubstring(self, s):
    dict = {c: 0 for c in s}
    begin, end, d, head = 0, 0, 0, 0
    while end < len(s):
        dict[s[end]] += 1
        while dict[s[end]] > 1:
            d = max(d, end - begin)
            dict[s[begin]] -= 1
            begin += 1
        end += 1
        if end == len(s):
            d = max(d, end - begin)
    return d

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值