指尖划过的轨迹,藏着最细腻的答案~
题目:
给你一个整数数组 nums 和两个正整数 m 和 k 。
请你返回 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 。
提示:
分析:
与【一看就会一写就废 指间算法】长度为 K 子数组中的最大和—— 滑动窗口、哈希表思路一样,不同之处在于本题窗口中的不同数字的数量限制为m。
定长滑动窗口一般分为三步走:
- 进入窗口:将当前值累加到窗口和
sum;由于我们从下标0开始遍历,因此在第一个窗口全部遍历完成之前,我们不应该进行第二步与第三步; - 更新答案:本题要求的是窗口中不相同数的数目,我们可以使用一个哈希表存储窗口中的数字,哈希表的长度就是不同数字的数量;如果大于m即满足题意,更新答案;
- 离开窗口:最左边的值此时已经超过了窗口的数量限制,将其从窗口中删除,同时同步更新哈希表。
AC代码:
class Solution {
public:
long long maxSum(vector<int>& nums, int m, 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() >= m) {
ans = max(ans, sum);
}
// 3. 离开窗口
int out = nums[left];
sum -= out;
if (--mp[nums[left]] == 0) {
mp.erase(nums[left]);
}
}
return ans;
}
};