leetcode_[python/C++]_395_Longest Substring with At Least K Repeating Characters_(递归非递归)

题目链接

【题目】
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.


【分析】

这道题写了老半天写不出来,无奈求助网上其他博主的做法,发现大家多是用了一种递归的方法,从起初的一整个字符串,然后在k约束条件下递归搜索不满足条件的字符位置的左边字符串和右边的字符串,从而记录最大值

想一想还是比较巧妙的

比如:

“abbcadda” 2

step 1: str = “abbcadda” 不满足条件的字符为c,因为只有c不满足至少重复2次,所以递归索引左右边字符串”abb” ,”adda”

—————————————————————————-左

step 2: str1 = “abb” 不满足条件的字符为a,递归”“ 和”bb”

———————左

step 3:str2 = “”

———————右

step 4:str3 = “bb” 满足条件,maxlen = 2

—————————————————————————-右

step 5:str4 = “adda” 满足条件,maxlen = 4 > 2

所以maxlen = 4, 即“adda”


先说一下递归的方法:
C++

int longestSubstring(const string &s, int k) {
    return helper(s, 0, s.size(), k);
}
int helper(const string &s, int beg, int end, int k){
    if(end - beg < k) return 0;
    int cnt[26]{};
    for(int i = beg; i < end; ++i) ++cnt[s[i]-'a'];
    for(int i = 0; i < 26; ++i)
        if (cnt[i] && cnt[i] < k)
            for(int j = beg; j < end; ++j)
                if(s[j] == i + 'a')
                    return max(helper(s, beg, j, k), helper(s, j + 1, end, k));
    return end - beg;
}

可以缩短为下面的写法:

int longestSubstring(const string &s, int k) {
    return helper(s, 0, s.size(), k);
}
int helper(const string &s, int beg, int end, int k){
    if(end - beg < k) return 0;
    int cnt[26]{};
    for(int i = beg; i < end; ++i) ++cnt[s[i]-'a'];
    for(int i = beg; i < end; ++i)
        if (cnt[s[i] - 'a'] < k)
            return max(helper(s, beg, i, k), helper(s, i + 1, end, k));
    return end - beg;
}

python:
利用python的splict函数可以这样写,极其简短:

def longestSubstring(self, s, k):
    if len(s) < k:
        return 0
    c = min(set(s), key=s.count)
    if s.count(c) >= k:
        return len(s)
    return max(self.longestSubstring(t, k) for t in s.split(c))

缩短:

def longestSubstring(self, s, k):
    for c in set(s):
        if s.count(c) < k:
            return max(self.longestSubstring(t, k) for t in s.split(c))
    return len(s)

非递归:

C++:
用了一种很巧妙地方法就是用一个int类型的二进制数来记录每一个字母是否重复大于k
因为是26个字母,所以int类型32位已经够了
如果>k:置为0
否则:置为1
当该int类型的数==0时,说明所有出现的字母都满足>k的条件,记录最小index跟最大index,求出maxlen

class Solution {
public:
    int longestSubstring(string s, int k) {
        int res = 0, i = 0, n = s.size();
        while (i + k < n) {
            int m[26] = {0}, mask = 0, max_idx = i;
            for (int j = i; j < n; ++j) {
                int t = s[j] - 'a';
                ++m[t];
                if (m[t] < k) mask |= (1 << t);
                else mask &= (~(1 << t));
                if (mask == 0) {
                    res = max(res, j - i + 1);
                    max_idx = j;
                }
            }
            i = max_idx + 1;
        }
        return res;
    }
};

python:

class Solution(object):
    def longestSubstring(self, s, k):
        ans,low,size = 0,0,len(s)
        while low + k < size:
            count = [0]*26
            mask,max_index = 0,low
            for high in range(low,size):
                chr_index = ord(s[high])-97
                count[chr_index] += 1
                if count[chr_index] < k:
                    mask |= (1<<chr_index)
                else:
                    mask &= (~(1<<chr_index))
                if not mask:
                    ans = max(ans,high - low + 1)
                    max_index = high
            low = max_index + 1
        return ans

当然,非递归的效率要比递归的快

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值