滑动窗口题目:删除子数组的最大得分

文章目录

题目

标题和出处

标题:删除子数组的最大得分

出处:1695. 删除子数组的最大得分

难度

5 级

题目描述

要求

给定一个正整数数组 nums \texttt{nums} nums,需要从中删除一个含有不同元素 的子数组。删除子数组的得分 是子数组各元素之

返回只删除一个 子数组可获得的最大得分

如果数组 b \texttt{b} b 是数组 a \texttt{a} a 的一个连续子序列,即如果它等于 a[l],a[l+1],...,a[r] \texttt{a[l],a[l+1],...,a[r]} a[l],a[l+1],...,a[r],那么它就是 a \texttt{a} a 的一个子数组。

示例

示例 1:

输入: nums = [4,2,4,5,6] \texttt{nums = [4,2,4,5,6]} nums = [4,2,4,5,6]

输出: 17 \texttt{17} 17

解释:最优子数组是 [2,4,5,6] \texttt{[2,4,5,6]} [2,4,5,6]。

示例 2:

输入: nums = [5,2,1,2,5,2,1,2,5] \texttt{nums = [5,2,1,2,5,2,1,2,5]} nums = [5,2,1,2,5,2,1,2,5]

输出: 8 \texttt{8} 8

解释:最优子数组是 [5,2,1] \texttt{[5,2,1]} [5,2,1] 或 [1,2,5] \texttt{[1,2,5]} [1,2,5]。

数据范围

  • 1 ≤ nums.length ≤ 10 5 \texttt{1} \le \texttt{nums.length} \le \texttt{10}^\texttt{5} 1≤nums.length≤105
  • 1 ≤ nums[i] ≤ 10 4 \texttt{1} \le \texttt{nums[i]} \le \texttt{10}^\texttt{4} 1≤nums[i]≤104

解法

思路和算法

由于数组 nums \textit{nums} nums 中的元素都是正整数,因此对于任意子数组,在子数组的任意一端添加元素(即增加子数组的长度)后子数组中的元素和一定增加,在子数组的任意一端删除元素(即减少子数组的长度)后子数组中的元素和一定减少。为了使删除子数组的得分最大,应该使子数组尽可能长。

考虑数组 nums \textit{nums} nums 的两个不同下标 end 1 \textit{end}_1 end1 和 end 2 \textit{end}_2 end2,其中 end 1 < end 2 \textit{end}_1 < \textit{end}_2 end1<end2,分别以这两个下标作为结束下标,寻找元素各不相同的最长子数组,将这两个最长子数组的开始下标分别记为 start 1 \textit{start}_1 start1 和 start 2 \textit{start}_2 start2,则必有 start 1 ≤ start 2 \textit{start}_1 \le \textit{start}_2 start1≤start2(否则对于任意 start 2 ≤ start 3 < start 1 \textit{start}_2 \le \textit{start}_3 < \textit{start}_1 start2≤start3<start1,下标范围 [ start 3 , end 1 ] [\textit{start}_3, \textit{end}_1] [start3,end1] 的子数组的元素各不相同,且长度大于下标范围 [ start 1 , end 1 ] [\textit{start}_1, \textit{end}_1] [start1,end1] 的子数组)。

因此,可以使用变长滑动窗口寻找数组 nums \textit{nums} nums 中的以每个下标作为结束下标的元素各不相同的最长子数组。用 [ start , end ] [\textit{start}, \textit{end}] [start,end] 表示滑动窗口,初始时 start = end = 0 \textit{start} = \textit{end} = 0 start=end=0。将滑动窗口的右端点 end \textit{end} end 向右移动,移动过程中维护滑动窗口的左端点 start \textit{start} start,对于每个 end \textit{end} end 寻找元素各不相同的最大滑动窗口。

为了判断滑动窗口中是否有重复元素,需要使用哈希集合存储滑动窗口中出现的元素。用 sum \textit{sum} sum 表示滑动窗口中的元素和。对于每个右端点 end \textit{end} end,将右端点处的元素记为 num = nums [ end ] \textit{num} = \textit{nums}[\textit{end}] num=nums[end],执行如下操作。

  1. 将 sum \textit{sum} sum 的值增加 num \textit{num} num。

  2. 如果哈希集合中有元素 num \textit{num} num,则滑动窗口 [ start , end ] [\textit{start}, \textit{end}] [start,end] 中有两个元素 num \textit{num} num,因此将 sum \textit{sum} sum 的值减去 nums [ start ] \textit{nums}[\textit{start}] nums[start],从哈希集合中移除元素 nums [ start ] \textit{nums}[\textit{start}] nums[start],然后将 start \textit{start} start 向右移动一位,重复该操作直到哈希集合中没有元素 num \textit{num} num。

  3. 当前滑动窗口 [ start , end ] [\textit{start}, \textit{end}] [start,end] 中的子数组为以 end \textit{end} end 作为结束下标的元素各不相同的最长子数组,其元素和为 sum \textit{sum} sum。使用 sum \textit{sum} sum 更新最大得分。

遍历结束之后,即可得到删除子数组的最大得分。

代码

java 复制代码
class Solution {
    public int maximumUniqueSubarray(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();
        int maxSum = 0;
        int sum = 0;
        int start = 0, end = 0;
        int length = nums.length;
        while (end < length) {
            int num = nums[end];
            sum += num;
            while (set.contains(num)) {
                sum -= nums[start];
                set.remove(nums[start]);
                start++;
            }
            set.add(num);
            maxSum = Math.max(maxSum, sum);
            end++;
        }
        return maxSum;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。滑动窗口的左右端点最多各遍历数组 nums \textit{nums} nums 一次。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。空间复杂度主要取决于哈希集合,哈希集合中每个元素最多出现一次。

相关推荐
递归尽头是星辰2 天前
双指针与滑动窗口算法精讲:从原理到高频面试题实战
算法·双指针·滑动窗口·子串/子数组问题
ゞ 正在缓冲99%…4 天前
leetcode438.找到字符串中所有字母异位词
leetcode·滑动窗口
3Cloudream5 天前
LeetCode 003. 无重复字符的最长子串 - 滑动窗口与哈希表详解
算法·leetcode·字符串·双指针·滑动窗口·哈希表·中等
HUIMU_11 天前
DAY20-新世纪DL(DeepLearning/深度学习)战士:终(目标检测/YOLO)3
深度学习·yolo·目标检测·滑动窗口·非极大值抑制·交并比·bouding box
蜡笔小柯南12 天前
每秒扛住10万请求?RedissonRateLimiter 分布式限流器详解
分布式·redisson·滑动窗口·ratelimiter
Dream it possible!14 天前
LeetCode 面试经典 150_滑动窗口_串联所有单词的子串(32_30_C++_困难)(滑动窗口:控制起点和滑动距离)
c++·leetcode·面试·滑动窗口
Q741_14719 天前
C++ 力扣 76.最小覆盖子串 题解 优选算法 滑动窗口 每日一题
c++·算法·leetcode·双指针·滑动窗口
Q741_1471 个月前
C++ 力扣 438.找到字符串中所有字母异位词 题解 优选算法 滑动窗口 每日一题
c++·算法·leetcode·双指针·滑动窗口
Tisfy1 个月前
LeetCode 837.新 21 点:动态规划+滑动窗口
数学·算法·leetcode·动态规划·dp·滑动窗口·概率