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 分钟前
贪心算法进阶:区间调度与最少资源整合解析
c++·python·算法·贪心·信息学竞赛·区间调度
青山木23 分钟前
Hot 100 --- 划分字母区间
java·数据结构·算法·leetcode·贪心算法
Sunsets_Red40 分钟前
浅谈扫描线
c++·算法·编程·题解·洛谷·扫描线·信息学竞赛
a1879272183142 分钟前
【算法】双指针与滑动窗口(一):框架总纲——三类问题、一个原理与判决书
算法·leetcode·区间·双指针·滑动窗口·原理·算法讲解
shehuiyuelaiyuehao1 小时前
算法42,模拟算法,模拟z字形变换
算法
朝朝辞暮i1 小时前
C++第一课
开发语言·c++·算法
橘子汽水1681 小时前
Leetcode 208,207实现Trie前缀树,课程表
java·数据结构·算法·leetcode
hanlin031 小时前
刷题笔记:力扣第169题-多数元素
笔记·算法·leetcode
hfywmsj1 小时前
广州餐饮铺位招租数据建模:基于多维评估体系的选址算法设计与实现
人工智能·算法·广州餐饮铺位招租
wabs6661 小时前
关于二叉树【力扣116.填充每个节点的下一个右侧节点指针的思考】
数据结构·c++·算法·leetcode·二叉树·层序遍历