Leetcode_395. Longest Substring with At Least K Repeating Characters_[Devide and Conquer]

题目链接

对一个字符串,找出一个最长的子串长度,这个子串中所有字符出现的次数至少为k。

1.滑动窗口

一开始把题目看成了,子串中每个字符至多出现k次。如果是这样,那么是一道典型的滑动窗口的题目。

然而,题目是至少出现k次。这样一来,滑动窗口不再适用。因为,在字符出现至多k次的问题中,当窗口尾部的字符超过k个,意味着只需要将窗口头部往后移动直至尾部字符等于k个;当尾部字符出现次数小于k次时,只需要将窗口尾部继续往后移动即可。而在字符出现至少k次的问题中,当尾部字符出现次数小于k次时,无法判断是移动窗口头部(舍弃尾部当前字符)还是移动窗口尾部(期待后面还有更多当前尾部字符)。

2.前缀和

然后想到了前缀和计数,然后用n^2的时间复杂度,检查每个子串是否满足所有字符至少出现k次。不出所料的超时。

3.一个想法

先对整个字符串的字符进行计数,假如存在出现次数少于k次的字符,那么目标串一定出现在被这个字符分隔开的几个字符串中。想到这里,我并没有得到什么更多的思路。。。

4.看了眼题解后

往深一步想,假如存在出现次数少于k次的字符,那么目标串一定出现在被这个字符分隔开的几个字符串中。那么,对这里的每一个分割产生的字符串,再求所有字符出现次数大于k的最长子串。不就得到原问题的一个子问题了吗?也就找到了递归关系。

class Solution {
public:
    vector<string> split(string s, char c){
        string temp;
        vector<string> ret;
        for(decltype(s.size())i=0; i<s.size(); i++){
            if(s[i] == c){
                if(temp.size()){
                    ret.push_back(temp);
                    temp = "";
                }
            }else{
                temp += s[i];
            }
        }
        if(temp.size())
            ret.push_back(temp);
        return ret;
    }

    int longestSubstring(string s, int k) {
        vector<int> ctr(26, 0);
        for(auto c : s)
            ctr[c-'a']++;
        int ret = 0, i;
        for(i=0; i<26; i++)
            if(ctr[i] > 0 && ctr[i] < k){
                auto substrs = split(s, i+'a');
                for(auto str : substrs)
                    ret = max(ret, longestSubstring(str, k));
                break;
            }
        if(i == 26)
            return s.size();
        return ret;
    }
};

 

原文地址:https://www.cnblogs.com/jasonlixuetao/p/11945760.html