本文涉及的基础知识点
C++算法:滑动窗口及双指针总结
LeetCode2516. 每种字符至少取 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
滑动窗口
n = s.length
nums[i…j-1]表示滑动窗口,其含义为:最终没有取走的。
令s中a,b,c的数量为cnta,cntb,cntc。则nums[i…j-1]中a,b,c的数量(令分别为a,b,c)小于等于cnta-k,cntb-k,cntc-k。
j一定是以下两种情况之一:
一,j == n。
二,a > cnta或b>cntb或c>cntc。
为了简化操作c1 = {a,b,c},c2={cnta,cntb,cntc}
结果就是 n - max(j-i)
注意:c2[i]<k直接返回-1。
时间复杂度:O(n)
代码
核心代码
class Solution {
public:
int takeCharacters(string s, int k) {
int c1[3] = { 0 }, c2[3] = { 0 };
for (int i = 0; i <3; i++) {
c2[i] = count(s.begin(), s.end(), 'a' + i);
}
if ((c2[0] < k) || (c2[1] < k) || (c2[2] < k)) { return -1; }
int ans = -1;
for (int i = 0, j = 0; i < s.length(); i++) {
while (j < s.length() ) {
const int inx = s[j] - 'a';
if ((c1[inx]+1 > c2[inx] - k)) { break; }
c1[inx]++; j++;
}
ans = max(ans, j - i);
c1[s[i] - 'a']--;
}
return s.length() - ans;
}
};
单元测试
string s;
int k;
TEST_METHOD(TestMethod11)
{
s = "aabaaaacaabc", k = 2;
auto res = Solution().takeCharacters(s, k);
AssertEx(8, res);
}
TEST_METHOD(TestMethod12)
{
s = "a", k = 2;
auto res = Solution().takeCharacters(s, k);
AssertEx(-1, res);
}
TEST_METHOD(TestMethod13)
{
s = "abc", k = 1;
auto res = Solution().takeCharacters(s, k);
AssertEx(3, res);
}