
Problem: 2841. 几乎唯一子数组的最大和
思路
子数组 ,定长 ,一定的条件限制,已经是条件反射了。立即推:滑动窗口。
解题方法
怎么滑?边界值出去的时候要怎么做?
-
怎么滑?定长的滑动窗口基本上直接确定这样的整体逻辑
jswhile (right - left + 1 > k) { sum -= nums[left] left++; } sum += nums[right] if (right - left + 1 === k) { ans = Math.max(ans, sum) }上述代码可以求全部的长度为
k的子数组的sum的最大值。接下来我们就是要过滤那些不符合题意的子数组(即只选取【几乎唯一子数组】) -
到底该怎么排除 那些不符合题意 的长度同样也为
k的子数组呢?- 确保至少有
m个不同的数字,也可以理解成重复数字的总数<= k - m - 因此,咱们可以用
repeatCount来记录当前长度为k的子数组中,重复数字的个数。
- 确保至少有
-
于是原来的代码就可以写成这样,只有满足题干条件的子数组 ,才有资格去和
ans作比较。jsif (right - left + 1 === k&& repeatCount <= k - m) { ans = Math.max(ans, sum) } -
接下来,问题就转变成了"如何去维护
repeatCount的值",什么时候加?什么时候减? -
于是我们通过一个
hashMap来记录当前遍历的数字是否出现过。-
如果出现过,则
repeatCount++, -
那么什么时候执行
repeatCount--呢?- 当数字从滑动窗口中被移出时,且通过
hashMapget到此数字的值大于1时 ,才执行repeatCount--。因为当这个数字都要被踢出滑动窗口了,它在hashMap中记录的值还是1的话,就说明这个数字一直以来都没有重复过,因此没必要让repeatCount--。
- 当数字从滑动窗口中被移出时,且通过
-
最终我们得到如下代码:
js
for (let right = 0; right < nlen; right++) {
while (right - left + 1 > k) {
if (hash.get(nums[left]) > 1) {
if (repeatCount > 0) {
repeatCount--;
}
}
if (hash.get(nums[left]) > 0) {
hash.set(nums[left], hash.get(nums[left]) - 1)
}
if (hash.get(nums[left]) === 0) {
hash.delete(nums[left])
}
sum -= nums[left]
left++
}
if (hash.has(nums[right])) {
hash.set(nums[right], hash.get(nums[right]) + 1)
repeatCount++;
}
else {
hash.set(nums[right], 1)
}
sum += nums[right]
if (right - left + 1 === k && repeatCount <= k - m) {
ans = Math.max(ans, sum)
}
复杂度
时间复杂度:
O(n)
空间复杂度:
O(n)
Code
js
/**
* @param {number[]} nums
* @param {number} m
* @param {number} k
* @return {number}
*/
var maxSum = function (nums, m, k) {
let left = 0;
let nlen = nums.length;
let hash = new Map();
let repeatCount = 0;
let sum = 0;
let ans = 0;
for (let right = 0; right < nlen; right++) {
while (right - left + 1 > k) {
if (hash.get(nums[left]) > 1) {
if (repeatCount > 0) {
repeatCount--;
}
}
if (hash.get(nums[left]) > 0) {
hash.set(nums[left], hash.get(nums[left]) - 1)
}
if (hash.get(nums[left]) === 0) {
hash.delete(nums[left])
}
sum -= nums[left]
left++
}
if (hash.has(nums[right])) {
hash.set(nums[right], hash.get(nums[right]) + 1)
repeatCount++;
}
else {
hash.set(nums[right], 1)
}
sum += nums[right]
if (right - left + 1 === k && repeatCount <= k - m) {
ans = Math.max(ans, sum)
}
}
return ans;
};