【題目】
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
當然,非遞歸的效率要比遞歸的快