leetcode
leetcode 2501 ~ 2550
统计最大元素出现至少 K 次的子数组

统计最大元素出现至少 K 次的子数组

难度:

标签:

题目描述

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.

 

Example 1:

Input: nums = [1,3,2,3,3], k = 2
Output: 6
Explanation: The subarrays that contain the element 3 at least 2 times are: [1,3,2,3], [1,3,2,3,3], [3,2,3], [3,2,3,3], [2,3,3] and [3,3].

Example 2:

Input: nums = [1,4,2,1], k = 3
Output: 0
Explanation: No subarray contains the element 4 at least 3 times.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 106
  • 1 <= k <= 105

代码结果

运行时间: 100 ms, 内存: 27.0 MB


/*
 * 题目思路:
 * 给定一个整数数组 nums 和一个正整数 k,要求统计所有满足 nums 中的最大元素至少出现 k 次的子数组。
 * 使用 Java Stream 的方法实现:
 * 1. 使用嵌套循环生成所有子数组。
 * 2. 对每一个子数组,使用流处理找到最大值及其出现次数。
 * 3. 统计满足条件的子数组数量。
 */

import java.util.stream.IntStream;

public class Solution {
    public long countSubarrays(int[] nums, int k) {
        return IntStream.range(0, nums.length)
                .flatMap(i -> IntStream.range(i, nums.length)
                        .mapToObj(j -> IntStream.rangeClosed(i, j).map(idx -> nums[idx]).toArray())
                )
                .filter(subarray -> {
                    int max = IntStream.of(subarray).max().orElse(Integer.MIN_VALUE);
                    long maxCount = IntStream.of(subarray).filter(x -> x == max).count();
                    return maxCount >= k;
                })
                .count();
    }
}

解释

方法:

本题解使用了双指针方法来统计满足条件的子数组数量。首先,找到数组中的最大元素t。然后,使用两个指针left和right来遍历数组,right指针向右移动来扩展当前考虑的子数组,left指针向右移动来缩小子数组。当子数组中最大元素t的出现次数达到k时,left指针开始移动,直到t的出现次数再次小于k。这样,对于每个right指针的位置,都可以计算出以right为结束点的、满足条件的子数组数量,即left指针当前的位置数。最后,将所有这些数量累加起来即为答案。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
如何确保双指针策略能够准确统计所有满足条件的子数组,而不会错过任何一个可能的子数组?
双指针策略通过维护一个动态的窗口来确保不漏掉任何符合条件的子数组。右指针`right`负责扩展窗口以包括更多元素,而左指针`left`则在条件满足(最大元素出现次数达到k)后开始移动以缩小窗口直到条件不再满足。每次右指针移动后,窗口内的所有以`right`为结束点的子数组都会被考虑,因为通过移动左指针,我们可以找到所有可能的以`right`为结束点的子数组的起始点。这样可以确保每个符合条件的子数组都被精确地统计一次。
🦆
在题解中,当最大元素t的计数达到k时,左指针开始移动直到计数再次小于k。这种操作是否可能导致对某些子数组的重复计数?
题解中的策略不会导致子数组的重复计数。当最大元素的计数达到k时,左指针移动是为了找到新的子数组的起始点,每移动一次左指针,代表原先计数的子数组已经不再被考虑,因此每个子数组只会被计算一次。左指针的每一次移动都对应着一个新的子数组起始点的确定,从而确保计数的唯一性。
🦆
题解中提到累加左指针的位置数来统计满足条件的子数组数量,这个方法的正确性依据是什么?
题解中累加左指针的位置数的方法基于每次右指针扩展后,左指针位置到右指针位置形成的区间内的所有子数组都是满足条件的子数组。因此,对于每个右指针位置,只需要累加左指针的位置数即可得到以该右指针位置为结束点的所有满足条件的子数组数量。这是因为每个以`right`为结束点的子数组都可以通过左指针的不同位置唯一确定。
🦆
当数组中最大值t的出现次数超过k时,如何处理这些额外的出现次数以确保统计的精确性?
当最大值t的出现次数超过k时,左指针继续移动直到最大元素的出现次数减少到小于k。这个过程确保了每个计数的子数组都恰好或至少包含k次最大元素,但不会引入额外的计数。只有当最大元素的计数达到或超过k,子数组才符合条件,左指针的移动是为了确保所有统计的子数组始终满足最大元素至少出现k次的条件。

相关问题