【一看就会一写就废 指间算法】长度为 K 子数组中的最大和—— 滑动窗口、哈希表

1 阅读2分钟

指尖划过的轨迹,藏着最细腻的答案~

题目:

给你一个整数数组 nums 和一个整数 k 。请你从 nums 中满足下述条件的全部子数组中找出最大子数组和:

  • 子数组的长度是 k,且
  • 子数组中的所有元素 各不相同 。

返回满足题面要求的最大子数组和。如果不存在子数组满足这些条件,返回 0

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

示例 1:

输入:nums = [1,5,4,2,9,9,9], k = 3
输出:15
解释:nums 中长度为 3 的子数组是:

  • [1,5,4] 满足全部条件,和为 10 。
  • [5,4,2] 满足全部条件,和为 11 。
  • [4,2,9] 满足全部条件,和为 15 。
  • [2,9,9] 不满足全部条件,因为元素 9 出现重复。
  • [9,9,9] 不满足全部条件,因为元素 9 出现重复。
    因为 15 是满足全部条件的所有子数组中的最大子数组和,所以返回 15 。

示例 2:

输入:nums = [4,4,4], k = 3
输出:0
解释:nums 中长度为 3 的子数组是:

  • [4,4,4] 不满足全部条件,因为元素 4 出现重复。
    因为不存在满足全部条件的子数组,所以返回 0 。

提示:

1knums.length1051 \leq k \leq nums.length \leq 10^5
1nums[i]1051 \leq nums[i] \leq 10^5

分析:

定长滑动窗口一般分为三步走:

  • 进入窗口:将当前值累加到窗口和sum;由于我们从下标0开始遍历,因此在第一个窗口全部遍历完成之前,我们不应该进行第二步与第三步;
  • 更新答案:本题要求的是窗口中不相同数的数目,我们可以使用一个哈希表存储窗口中的数字,哈希表的长度size就是不同数字的数量;如果size == k即满足题意,更新答案;
  • 离开窗口:最左边的值此时已经超过了窗口的数量限制,将其从窗口中删除,同时同步更新哈希表。

AC代码:

class Solution {
public:
    long long maximumSubarraySum(vector<int>& nums, int k) {
        long long ans = 0, sum = 0;
        unordered_map<int, int> mp;

        for (int i = 0; i < nums.size(); i++) {
            // 1. 进入窗口
            sum += nums[i];
            mp[nums[i]]++;

            int left = i - k + 1;
            if (left < 0) {
                continue;
            }

            // 2. 更新答案
            if (mp.size() == k) {
                ans = max(ans, sum);
            }

            // 3. 离开窗口
            int out = nums[left];
            sum -= out;
            if (--mp[nums[left]] == 0) {
                mp.erase(nums[left]);
            }
        }

        return ans;
    }
};