1500分的题目,确实有实力,不过还是我略胜一筹

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

  1. 思路
  2. 解题方法
  3. 复杂度
  4. Code

思路

子数组定长 ,一定的条件限制,已经是条件反射了。立即推:滑动窗口

解题方法

怎么滑?边界值出去的时候要怎么做?

  • 怎么滑?定长的滑动窗口基本上直接确定这样的整体逻辑

    js 复制代码
       while (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作比较。

    js 复制代码
            if (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;

};
相关推荐
海石1 小时前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
Jerry3 小时前
LeetCode 151. 反转字符串中的单词
算法
a1117765 小时前
LM 算法迭代过程动画演示(SLAM)
算法
头茬韭菜5 小时前
Context 的生死抉择:四层压缩、截断算法与 Session Memory
算法·ai
Jerry6 小时前
LeetCode 541. 反转字符串 II
算法
Jerry6 小时前
LeetCode 344. 反转字符串
算法
搞科研的小刘选手6 小时前
【香港大学主办&IEEE出版】第六届计算机视觉、应用与算法国际学术会议(CVAA 2026)
算法·计算机视觉·应用·学术会议
Java小白笔记6 小时前
Codex config.toml配置实战指南
人工智能·算法·chatgpt·ai编程·集成学习
王老师青少年编程6 小时前
2026年6月GESP真题及题解(C++七级):消消乐
数据结构·c++·算法·真题·gesp·2026年6月