开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第22天,点击查看活动详情
问题描述
给你一个长度为 n 下标从 0 开始的字符串 blocks ,blocks[i] 要么是 'W' 要么是 'B' ,表示第 i 块的颜色。字符 'W' 和 'B' 分别表示白色和黑色。
给你一个整数 k ,表示想要 连续 黑色块的数目。
每一次操作中,你可以选择一个白色块将它 涂成 黑色块。
请你返回至少出现 一次 连续 k 个黑色块的 最少 操作次数。
示例 1:
输入: blocks = "WBBWWBBWBW", k = 7
输出: 3
解释:
一种得到 7 个连续黑色块的方法是把第 0 ,3 和 4 个块涂成黑色。
得到 blocks = "BBBBBBBWBW" 。
可以证明无法用少于 3 次操作得到 7 个连续的黑块。
所以我们返回 3 。
示例 2:
输入: blocks = "WBWBBBW", k = 2
输出: 0
解释:
不需要任何操作,因为已经有 2 个连续的黑块。
所以我们返回 0 。
提示:
n == blocks.length1 <= n <= 100blocks[i]要么是'W',要么是'B'。1 <= k <= n
思路分析
首先我们要先理解一下题意,题目会给我们一个字符串blocks和一个整数K,blocks字符串中只包含W和B两种字符,其中W代表白色,B代表黑色,我们想要得到一串长度为k且全部字符都为B的字符串,我们可以对blocks字符串进行染色操作,也就是将其中的W字符进行染色将其变成B,我们需要计算我们至少需要染色的次数。
这里给了我们需要得到字符串的长度为k,我们只需要计算获取该字符串需要进行的操作数,这个长度是不会变的,那么我们可以将其看成一个窗口,只需要计算窗口中字符串所需染色的个数,后面不断地将窗口右移,维护更新染色操作数即可。
- 1、确定第一个窗口
我们先计算blocks字符串的前k个字符中有多少个需要进行染色,及W字符的个数,此时窗口的左端点的0,右端点为k,操作数为cnt。
let sum = 0,cnt = 0,left = 0;
for(let i = 0; i < k; i++){
if(blocks[i] == 'W') cnt++;
}
sum = cnt;
- 2、右移窗口
右移窗口只需要每次同时将左端点和右端点向右移动一格即可,右移的时候我们会舍弃掉原窗口内的左端点字符,并纳入右端点一个新的字符,我们需要计算舍弃的字符和新增字符对操作数的影响:如果舍弃的字符为W,那么我们的操作数应该减一,即减去原对舍弃字符进行的操作;如果新增的字符为W,那么我们需要将操作数加一,因为我们要保证窗口内的字符都为B。
for(let i = k; i < blocks.length; i++){
if(blocks[i] === 'W') cnt++;
if(blocks[left++] === 'W') cnt--;
sum = Math.min(sum,cnt);
}
AC代码
完整代码如下:
/**
* @param {string} blocks
* @param {number} k
* @return {number}
*/
var minimumRecolors = function(blocks, k) {
let sum = 0,cnt = 0,left = 0;
for(let i = 0; i < k; i++){
if(blocks[i] == 'W') cnt++;
}
sum = cnt;
for(let i = k; i < blocks.length; i++){
if(blocks[i] === 'W') cnt++;
if(blocks[left++] === 'W') cnt--;
sum = Math.min(sum,cnt);
}
return sum;
};
说在后面
本人为算法业余爱好者,平时只是随着兴趣偶尔刷刷题,如果上面分享有错误的地方,欢迎指出,感激不尽。