LeetCode 395. Longest Substring with At Least K Repeating Characters(Medium)题解

查阅更多的题解,请点击

Problem

395. Longest Substring with At Least K Repeating Characters(Medium)

Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times.

Example 1:

Input:
s = "aaabb", k = 3

Output:
3

The longest substring is "aaa", as 'a' is repeated 3 times.

Example 2:

Input:
s = "ababbc", k = 2

Output:
5

The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.

Solution

设字符串s的长度为n

O(n^2) time

解决该问题最朴素的想法就是枚举所有的情况:枚举前n-k个字符作为substring的开头的所有情况。

在枚举过程中,需要判断当前枚举的子串是否满足每个字符都出现至少k次,由于最多只有26个字符,则可以用一个整数,数的一个二进制位来对应一个字符是否出现至少k次,比如,整数最低的二进制代表字符a,该位为0,则代表:

  • 子串中未出现字符a
  • 子串中出现字符a且a至少出现了k次

该算法在最坏情况下是O(n^2) time

class Solution
{
public:
    int longestSubstring(string s, int k)
    {
        if (s.size() < k)
            return 0;
        int n = s.size();
        int res = 0;
        for (int begin = 0; begin + k <= n;)
        {
            vector<int> count(26, 0);
            int isAllMatch = 0;
            int end = begin;
            int maxEnd = begin;
            for (; end < n; ++end)
            {
                int cur = s[end] - 'a';
                count[cur]++;
                if (count[cur] >= k)
                    isAllMatch &= (~(1 << cur));
                else
                    isAllMatch |= (1 << cur);

                //catch a substring which meets the condition.
                if (isAllMatch == 0)
                {
                    res = max(end - begin + 1, res);
                    maxEnd = end;
                }
            }
            begin = maxEnd + 1;
        }
        return res;
    }
};

O(n) time

观察原问题是否可以reduce,满足题意的子串中每个字符都至少出现k次,则原字符串中出现次数少于k次的字符,一定不会出现在解中,我们可以依据这些出现次数少于k次的字符对原字符串进行划分,在子问题中求解(若字符串不存在出现次数少于k的字符,则该字符串就是所求解)

子问题显然不多于26个,最坏情况下子问题求解是O(n) time的,所以原问题是O(n) time的

class Solution
{
private:
    int getLongestSubstring(string &s, int begin, int end, int k)
    {
        vector<int> count(26, 0);
        for (int i = begin; i < end; ++i)
        {
            count[s[i] - 'a']++;
        }
        int res = 0;
        for (int i = begin; i < end;)
        {
            //find the first char which appears no less than k
            while (i < end && count[s[i] - 'a'] < k)
                i++;
            if (i == end)
                break;
            int j = i;

            //find the first char which appears less than k
            while (j < end && count[s[j] - 'a'] >= k)
                j++;

            //find an substring which matches the condiation.
            if (i == begin && j == end)
                return end - begin;
            res = max(res, getLongestSubstring(s, i, j, k));
            i = j + 1;
        }
        return res;
    }

public:
    int longestSubstring(string s, int k)
    {
        if (s.size() < k)
            return 0;
        return getLongestSubstring(s, 0, s.size(), k);
    }
};

GitHub传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值