需求
找到給定字符串(由小寫字符組成)中的最長子串 T , 要求 T 中的每一字符出現次數都不少於 k 。輸出 T 的長度。
示例 1:
輸入:
s = "aaabb", k = 3
輸出:
3
最長子串爲 "aaa" ,其中 'a' 重複了 3 次。
示例 2:
輸入:
s = "ababbc", k = 2
輸出:
5
最長子串爲 "ababb" ,其中 'a' 重複了 2 次, 'b' 重複了 3 次。
思路:分治,遞歸
遍歷一遍字符串,找到各個字符出現的位置並統計各個字符出現的次數,若字符出現次數小於k,則該字符出現的位置即爲分割點。
找到所有分割點,排序分割點,對相鄰分割點之間的區間遞歸調用此算法。得出最大值,完成。
時間複雜度:分治一般是O(nlogn)。這裏分析下最壞情況,每一遍掃描或者找到分割點,進行下一次遞歸,或者沒有找到分割點,結束。所以最壞的情況下是每次找到一個分割點,即一次刪除一個元素,而刪除一個元素時間複雜度爲O(n),整體最壞情況下時間複雜度爲O(n^2)。
代碼
class Solution {
public:
int longestSubstring(string s, int k) {
if(s.size()<k) return 0;
map<char,vector<int> > pos;
vector<int> span;
for(int i=0;i<s.size();++i){
if(pos.count(s[i])>0){
pos[s[i]].push_back(i);
}else{
pos[s[i]]={i};
}
}
for(auto kv:pos){
auto v=kv.second;
if(v.size()<k){
for(auto& i:v){
span.push_back(i);
}
}
}
if(span.size()<1) return s.size();
sort(span.begin(),span.end());
int i=0,j;
int ret=0;
for(int m=0;m<span.size();++m){
j=span[m];
ret=max(ret,findSub(s,k,i,j));
i=j+1;
}
ret=max(ret,findSub(s,k,j+1,s.size()));
return ret;
}
int findSub(string s,int k,int start,int end){
if(end-start<k) return 0;
return longestSubstring(s.substr(start,end-start),k);
}
};