leetcode 2461.长度为k子数组的最大和

目录

题目描述

示例1:

示例2:

提示:

解题思路

滑动窗口法

概念

应用场景及特点:

思路

流程展示

代码

复杂度分析


题目描述

给你一个整数数组nums和一个整数k。请你从nums中满足下述条件的全部子数组中找出最大子数组和:

  • 子数组的长度是k,且
  • 子数组中的所有元素各不相同

返回满足题面要求的最大子数组和。如果不存在子数组满足这些条件,返回0
子数组是数组中一段连续非空的元素序列。

示例1:

输入:nums = [1,5,4,2,9,9,9], k = 3
输出:15
解释:nums 中长度为 3 的子数组是:
- [1,5,4] 满足全部条件,和为 10 。
- [5,4,2] 满足全部条件,和为 11 。
- [4,2,9] 满足全部条件,和为 15 。
- [2,9,9] 不满足全部条件,因为元素 9 出现重复。
- [9,9,9] 不满足全部条件,因为元素 9 出现重复。
因为 15 是满足全部条件的所有子数组中的最大子数组和,所以返回 15 。

示例2:

输入:nums = [4,4,4], k = 3
输出:0
解释:nums 中长度为 3 的子数组是:
- [4,4,4] 不满足全部条件,因为元素 4 出现重复。
因为不存在满足全部条件的子数组,所以返回 0 。

提示:

  • 1 <= k <= nums.length <= 105
  • 1 <= nums[i] <= 105

解题思路

滑动窗口法

概念

滑动窗口是一个在序列上移动的区间,通常由左右两个指针来界定这个区间的范围。通过移动指针来改变窗口的大小和位置,在窗口移动的过程中,根据问题的需求进行特定的计算和处理。

应用场景及特点

  1. 子数组 / 子串问题
  • 当需要在一个序列中找到满足特定条件的连续子数组或子串时,滑动窗口非常适用。例如,寻找和为特定值的连续子数组、含有特定字符的最长子串等。
  • 窗口的大小通常是动态变化的,根据问题的条件进行调整。
  1. 高效性
  • 相比于暴力枚举所有可能的子数组 / 子串,滑动窗口法通常能够在更短的时间内找到解。因为它利用了子数组 / 子串的连续性和窗口的滑动特性,避免了重复计算。
  1. 指针移动规则
  • 通常有两个指针,一个指向窗口的左端,一个指向窗口的右端。根据问题的具体要求,以特定的方式移动指针。
  • 例如,在寻找满足特定条件的最小子数组时,可能会先扩大窗口直到满足条件,然后再缩小窗口以找到最小的满足条件的窗口。

思路

  1. 初始化
  • 使用一个滑动窗口,窗口大小为 k
  • 创建一个计数器(可以使用 collections.Counter)来记录窗口中元素的出现次数。
  • 初始化当前窗口的和为 0,最大子数组和为 0。
  1. 滑动窗口遍历
  • 首先,将窗口的前 k 个元素加入窗口,并计算它们的和以及使用计数器记录元素出现次数。
  • 检查窗口中的元素是否各不相同。如果是,更新最大子数组和为当前窗口的和。
  • 然后,向右滑动窗口,每次将新元素加入窗口,将离开窗口的元素从计数器中移除,并更新窗口的和。
  • 再次检查窗口中的元素是否各不相同。如果是,与当前最大子数组和比较并更新。
  1. 返回结果
  • 遍历完整个数组后,返回最大子数组和。

流程展示

代码

class Solution:
    def maximumSubarraySum(self, nums: List[int], k: int) -> int:
        ans = 0
        cnt = Counter(nums[:k-1])
        s = sum(nums[:k-1])

        for in_,out in zip(nums[k-1:],nums):
            cnt[in_] += 1
            s += in_

            if len(cnt) == k:
                ans = max(ans, s)
            cnt[out] -= 1
            if cnt[out] == 0:
                del cnt[out]
            s -= out

        return ans

复杂度分析

  • 时间复杂度:由于只需要对数组进行一次遍历,时间复杂度为 O(n),其中 n 是数组的长度。
  • 空间复杂度:使用了计数器和有限的几个变量,空间复杂度为 O(k),其中 k 是窗口的大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值