每个字符至少取K个
题干
给你一个由字符 'a'
、'b'
、'c'
组成的字符串 s
和一个非负整数 k
。每分钟,你可以选择取走 s
最左侧 还是 最右侧 的那个字符。
你必须取走每种字符 至少 k
个,返回需要的 最少 分钟数;如果无法取到,则返回 -1
。
示例 1:
输入:s = "aabaaaacaabc", k = 2 输出:8 解释: 从 s 的左侧取三个字符,现在共取到两个字符 'a' 、一个字符 'b' 。 从 s 的右侧取五个字符,现在共取到四个字符 'a' 、两个字符 'b' 和两个字符 'c' 。 共需要 3 + 5 = 8 分钟。 可以证明需要的最少分钟数是 8 。
示例 2:
输入:s = "a", k = 1 输出:-1 解释:无法取到一个字符 'b' 或者 'c',所以返回 -1 。
提示:
1 <= s.length <= 105
s
仅由字母'a'
、'b'
、'c'
组成0 <= k <= s.length
思路:
1、滑动窗口
2、left和right两个边界,其中需要注意的是,left包含在子串中而right不含在子串中。
3、tar数组表示a、b、c三个字母在字符串s中的总数量-k
4、如果cnt数组即任意三个字母的数量大于tar数组,则移动left边界且减去相应的cnt数量
代码:
using namespace std;
class Solution {
public:
int takeCharacters(string s, int k) {
int left=0,right=0;
int max_len=0; //用于记录满足条件的最大子串长度
int total[3]={0};
total[0]=count(s.begin(),s.end(),'a')-k;
total[1]=count(s.begin(),s.end(),'b')-k;
total[2]=count(s.begin(),s.end(),'c')-k;
if(total[0] < 0 || total[1] < 0 || total[2]<0){
return -1;
}else if(total[0]==0 && total[1]==0 && total[2]==0){
return s.length();
}else{
int cnt[3]={0};
while(right<s.length()){
cnt[s[right++]-'a']++; //增加右指针字符的计数
//检查当前窗口是否符合要求
while(cnt[0]>total[0] || cnt[1]>total[1] || cnt[2]>total[2]){
cnt[s[left++]-'a']--;
}
max_len = max(max_len,right-left); //left包含在子串中,right不包含在子串中,所以这里不用-1
}
return s.length()-max_len;
}
}
};
收获:
1、c++中判断字符串中某个字符的出现个数可以用count(s.begin(),s.end(),'a')
2、利用某个字符减去'a'直接得到各字符的数组的数字位。