题目描述



解题思路
这一题本来在想怎么样做才能获得通用解,因为乍一看总感觉遍历的时间代价会非常高。直到后面看到提示:

提示里面专门包含了一个n < k * 8,这太反常了。后面仔细一想,有道理,最后答案的字符个数一定小于8,因为 字符数 乘 k一定得小于字符串的总长度,否则这个候选解一定无法重复k次。
那么这就直接给了我遍历的信心了。
那直接遍历,从2个字母的组合开始遍历直到8为止,满足条件的候选集里,再尝试接第三个候选字符,接第四个候选字符,直到接不了任何字母为止。而至于能否重复k次,直接遍历字符串,看看目前的候选解是否有k次。
唯一需要关注的是有哪些过滤条件:
- 首先,对每个字母出现的频率进行次数统计
- 候选解的每个字母出现的频率都必须>=k
- 在字符串每次匹配了一次候选解的时候都要判断候选字符的剩余个数能否支持k次重复
- 在添加候选字符时,如果目前的候选解里面包含这个候选字符,那设添加该候选字符后该字符在候选解中的总个数为m,那么cnt[候选字符] >= m * k(理论可以这样加速,但我懒没有实现)
- 添加候选字符时,按字典序高的优先添加,这样返回结果时直接返回candidate[0]就可以加速。
代码
string longestSubsequenceRepeatedK(string s, int k) {
vector<int> cnt;
vector<string> candidate;
cnt.resize(26);
for(int i = 0; i < s.size(); i++)
{
cnt[s[i] - 'a'] ++;
}
for(int i = 25; i >= 0; i--)
if(cnt[i] >= k)
candidate.emplace_back(string(1,i + 'a'));
for(int num = 2; num < 8; num++)
{
vector<string> new_candidate;
for(int i = 0; i < candidate.size(); i++)
{
int remain = 0;
char last = candidate[i].size() - 1;
for(int q = 25 ; q >= 0; q--)
{
remain = cnt[q];
if(remain < k) continue;
int curr_idx = 0;
int curr_k = k;
bool flag = true;
for(int idx = 0; idx < s.size(); idx ++)
{
if(flag && s[idx] == candidate[i][curr_idx])
{
if(curr_idx == last)
{
if(s[idx] == q + 'a') remain--;
if(remain < curr_k)
break;
curr_k --;
if(curr_k == 0)
{
new_candidate.emplace_back(candidate[i]+ char(q + 'a'));
break;
}
flag = false;
continue;
}
curr_idx = (curr_idx + 1)% candidate[i].size();
}
if(s[idx] == q + 'a')
{
remain --;
if(!flag)
{
curr_idx = 0;
flag = true;
}
}
}
}
}
if(new_candidate.empty()) break;
candidate.swap(new_candidate);
}
if(candidate.empty()) return "";
return candidate[0];
}
437

被折叠的 条评论
为什么被折叠?



