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;

};
相关推荐
索尔~古德曼3 分钟前
CF(1400-1400&1300-1500)错题集
算法
All for pursuit.1 小时前
【二分查找-2】34.在排序数组中查找元素的第一个和最后一个位置
数据结构·c++·算法·leetcode
泯泷1 小时前
为什么 AI 会"失忆"?——读懂 Agent 的记忆系统(一)
人工智能·算法·agent
需要8263 小时前
分布式 ID 生成:雪花算法、号段模式与时钟回拨
分布式·算法
垆边人似月.3 小时前
华为机考题:字符串分隔
算法·华为
CQU_JIAKE3 小时前
9.4【A】
算法
CQU_JIAKE3 小时前
9.13[A]
算法
懿路向前3 小时前
【唤醒实战笔记】2026-09-29 | 智能体提示词迭代史(v1 → v8)
linux·笔记·算法
@陈小鱼4 小时前
基于CNN-Transformer的无袖带血压估计
人工智能·深度学习·神经网络·算法·cnn·transformer·血压
黄金龙PLUS4 小时前
5个1280比特大状态置换算法的设计与分析
算法·网络安全·密码学·哈希算法·同态加密