diff --git a/content/posts/leetcode.md b/content/posts/leetcode.md index 18c8e1c..00d760b 100644 --- a/content/posts/leetcode.md +++ b/content/posts/leetcode.md @@ -2261,3 +2261,84 @@ func maxSubarrayLength(nums []int, k int) int { return res } ``` + +## day31 2024-03-29 + +### 2962. Count Subarrays Where Max Element Appears at Least K Times + +You are given an integer array nums and a positive integer k. + +Return the number of subarrays where the maximum element of nums appears at least k times in that subarray. + +A subarray is a contiguous sequence of elements within an array. + +![0329pKR0itEdYZ5b](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/0329pKR0itEdYZ5b.png) + +### 题解 + +本题感觉就是昨天那道题的姊妹+升级版, 现在要求找到数组中包含的最大值, 其在这个子数组中的出现次数至少为k次. 这里明确题目中需要解决的两个问题. 1. 找到数组中的最大值 2. 对这个值在子序列中出现的次数进行计数. 无疑, 仍然可以使用滑动窗口来解决, 思路和昨天的题类似, 这里在扩大窗口时, 一直扩大到最大值数目为k, 继续向后遍历时要每次增加从头开始到包含k个最大值的窗口的最左端的元素个数. 核心思路在于让滑动窗口中只保留k个最大值, 这样所有包含前面数据的子数组和包含后面不为最大值的子数组的所有子数组都符合条件. + +### 代码 + +```go +func countSubarrays(nums []int, k int) int64 { + max := slices.Max(nums) + var result int64 + left := 0 + nextleft := 0 + beforeadded := 0 + frequency := 0 + for _, value := range nums{ + if value == max{ + frequency++ + if frequency >= k{ + for nums[nextleft] != max{ + nextleft++ + } + beforeadded += nextleft - left + 1 + result += int64(beforeadded) + left = nextleft+1 + nextleft = left + } + }else if frequency >= k{ + result += int64(beforeadded) + } + + } + + return result +} + +``` + +### 总结 + +查看他人的题解发现, 可以在保持窗口内最大值个数为k的思路下优化解题过程, 重复的加前面的元素是不必要的, 先将所有最大值的下标放入数组, 然后确定包含k个最大值的窗口的两端的下标, 将该窗口左侧前面的元素个数和窗口右侧后面的元素个数相乘即为该窗口对应的符合条件的解的个数, 切换到下一个包含k个最大值的窗口, 继续此操作, 直到窗口中最大值数目不足k为止. + +```go +func countSubarrays(nums []int, k int) int64 { + var m int + for _, n := range nums { + m = max(m, n) + } + var idxs []int + for i := range nums { + if nums[i] == m { + idxs = append(idxs, i) + } + } + start := 0 + count := int64(0) + for i := range idxs { + if i+k > len(idxs) { + break + } + last := len(nums) + if i+k < len(idxs) { + last = idxs[i+k] + } + count += int64(idxs[i]-start+1) * int64(last-idxs[i+k-1]) + } + return count +} +```