2090. 半径为 k 的子数组平均值
题目来源:2090. 半径为 k 的子数组平均值 - 力扣(LeetCode)
题目:
分析:
- 由于半径为k,那么window就是 2 *k + 1,所以这是一个定长滑动窗口
- 那么定长滑动窗口端点指针的关系就是 :
- right - left +1 = 2*k +1
- left = right - 2*k
- 由于i索引前后半径不够k avg直接赋值为-1:
- 如果len(nums) < len(window) return [i for i in range(len(nums))]
- 如果条件一满足,那么left < 0 or right > len(nums) -1 时,avg = -1
- 因为right作为window右端点,那么如果加和随着索引i相加就会遗漏sum(nums[k:right + 1]),所以我首先想到了随right索引加和,将加和结果变量初始化为sum(nums[:k]),这样就可以实现滑动窗口的移动和移除
我的解:
class Solution:
def getAverages(self, nums: List[int], k: int) -> List[int]:
# 窗口长度为 2k + 1
windows = 2*k + 1
ans = list()
length = len(nums)
# 前或后不足 k 个元素 半径为 k 的子数组平均值 是 -1
if length < windows:
return [-1 for i in range(length)]
left = 0
# 初始化
add = sum(nums[:k])
for i in range(length):
right = i + k
left = right - 2*k
if right >= length:
ans.append(-1)
continue
else:
add += nums[right]
if left < 0 :
ans.append(-1)
continue
# 更新 ans 数组
ans.append(add//len(nums[left:right+1]))
# 移除 windows末端数值
add -= nums[left]
return ans
题解:
class Solution:
def getAverages(self, nums: List[int], k: int) -> List[int]:
avgs = [-1] * len(nums)
s = 0 # 维护窗口元素和
for i, x in enumerate(nums):
# 1. 进入窗口
s += x
if i < k * 2: # 窗口大小不足 2k+1
continue
# 2. 记录答案
avgs[i - k] = s // (k * 2 + 1)
# 3. 离开窗口
s -= nums[i - k * 2]
return avgs
结论:
- avgs = [-1] * len(nums) 初始化只需要O(1),后面遍历处理的数据量小于n
- 我的代码中初始化求sum以及根据窗口判断更新ans都会增加耗时
2379. 得到 K 个黑块的最少涂色次数
题目来源:2379. 得到 K 个黑块的最少涂色次数 - 力扣(LeetCode)
解答:
class Solution:
def minimumRecolors(self, blocks: str, k: int) -> int:
ans = inf
left = 0
length = len(blocks)
data = {'W':0,'B':0}
for right in range(length):
data[blocks[right]] += 1
left = right + 1 - k
if left < 0:
continue
ans = min(ans,data['W'])
data[blocks[left]] -= 1
return ans