Skip to content

2841. 几乎唯一子数组的最大和 Medium

给你一个整数数组 nums 和两个正整数 mk

请你返回 nums 中长度为 k 的 几乎唯一 子数组的 最大和 ,如果不存在几乎唯一子数组,请你返回 0

如果 nums 的一个子数组有至少 m 个互不相同的元素,我们称它是 几乎唯一 子数组。

子数组指的是一个数组中一段连续 非空 的元素序列。

示例 1:
输入:nums = [2,6,7,3,1,7], m = 3, k = 4
输出:18
解释:总共有 3 个长度为 k = 4 的几乎唯一子数组。分别为 [2, 6, 7, 3] ,[6, 7, 3, 1] 和 [7, 3, 1, 7] 。这些子数组中,和最大的是 [2, 6, 7, 3] ,和为 18 。

示例 2:
输入:nums = [5,9,9,2,4,5,4], m = 1, k = 3
输出:23
解释:总共有 5 个长度为 k = 3 的几乎唯一子数组。分别为 [5, 9, 9] ,[9, 9, 2] ,[9, 2, 4] ,[2, 4, 5] 和 [4, 5, 4] 。这些子数组中,和最大的是 [5, 9, 9] ,和为 23 。

示例 3:
输入:nums = [1,2,1,2,1,2,1], m = 3, k = 3
输出:0
解释:输入数组中不存在长度为 k = 3 的子数组含有至少 m = 3 个互不相同元素的子数组。所以不存在几乎唯一子数组,最大和为 0 。

解题思路

输入:一个整数数组 nums 和两个正整数 mk

输出:返回一个子数组的和,子数组长度要等于 k 并且不重复元素数量要 >= m

本题属于 固定长度滑动窗口类型 类型。

我们已知窗口长度为 k,这道题的难点在于要记录窗口内不重复元素的数量,满足数量 >= m 的窗口才记录答案

所以我们需要用一个 HashMap freq 记录窗口内元素的出现频率

我们可以从 0 开始扩张窗口长度,当大于 k 的时候意味着要缩小窗口,此时移除左端口并且更新窗口内元素频率

每次都判断当窗口长度为 k 并且不重复元素数量 >= m,满足条件则记录答案

代码实现

python
from typing import List

class Solution:
    def maxSum(self, nums: List[int], m: int, k: int) -> int:
        # 初始化哈希表记录窗口内数字的频率
        freq = {}
        # 初始化最大和
        max_sum = 0
        # 初始化窗口左边界
        left = 0
        # 初始化窗口内元素的和
        window_sum = 0
        
        # 遍历数组,使用右指针 r 扩展窗口
        for right in range(len(nums)):
            num = nums[right]
            # 更新窗口和
            window_sum += num
            # 更新频率表
            freq[num] = freq.get(num, 0) + 1
            
            # 如果窗口大小超过 k,收缩窗口
            if right - left + 1 > k:
                left_num = nums[left]
                # 减去左边界元素的值
                window_sum -= left_num
                # 更新频率表
                freq[left_num] -= 1
                # 如果某个数字的频率为 0,删除该数字
                if freq[left_num] == 0:
                    del freq[left_num]
                # 左指针右移
                left += 1
            
            # 当窗口大小正好为 k 且唯一数字数量不少于 m 时,更新最大和
            if right - left + 1 == k and len(freq) >= m:
                max_sum = max(max_sum, window_sum)
        
        return max_sum
javascript
/**
 * @param {number[]} nums
 * @param {number} m - 至少有多少种不同元素
 * @param {number} k - 子数组长度固定为 k
 * @return {number}
 */
var maxSum = function(nums, m, k) {
    let left = 0;
    let total = 0;
    let maxSum = 0;
    const freq = new Map();

    for (let right = 0; right < nums.length; right++) {
        const num = nums[right];
        total += num;
        freq.set(num, (freq.get(num) || 0) + 1);

        // 窗口大于 k 时,收缩左边界
        if (right - left + 1 > k) {
            const leftNum = nums[left];
            total -= leftNum;
            freq.set(leftNum, freq.get(leftNum) - 1);
            if (freq.get(leftNum) === 0) freq.delete(leftNum);
            left++;
        }

        // 窗口刚好为 k 且不同元素种类数 ≥ m
        if (right - left + 1 === k && freq.size >= m) {
            maxSum = Math.max(maxSum, total);
        }
    }

    return maxSum;
};

复杂度分析

时间复杂度:O(n)

空间复杂度:O(1)

链接

2730 国际版

2730 中文版