Skip to content

Latest commit

 

History

History

2841.Maximum Sum of Almost Unique Subarray

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

English Version

题目描述

给你一个整数数组 nums 和两个正整数 m 和 k 。

请你返回 nums 中长度为 k 的 几乎唯一 子数组的 最大和 ,如果不存在几乎唯一子数组,请你返回 0 。

如果 nums 的一个子数组有至少 m 个互不相同的元素,我们称它是 几乎唯一 子数组。

子数组指的是一个数组中一段连续 非空 的元素序列。

 

示例 1:

输入:nums = [2,6,7,3,1,7], m = 3, k = 4
输出:18
解释:总共有 3 个长度为 k = 4 的几乎唯一子数组。分别为 [2, 6, 7, 3] ,[6, 7, 3, 1] 和 [7, 3, 1, 7] 。这些子数组中,和最大的是 [2, 6, 7, 3] ,和为 18 。

示例 2:

输入:nums = [5,9,9,2,4,5,4], m = 1, k = 3
输出:23
解释:总共有 5 个长度为 k = 3 的几乎唯一子数组。分别为 [5, 9, 9] ,[9, 9, 2] ,[9, 2, 4] ,[2, 4, 5] 和 [4, 5, 4] 。这些子数组中,和最大的是 [5, 9, 9] ,和为 23 。

示例 3:

输入:nums = [1,2,1,2,1,2,1], m = 3, k = 3
输出:0
解释:输入数组中不存在长度为 k = 3 的子数组含有至少  m = 3 个互不相同元素的子数组。所以不存在几乎唯一子数组,最大和为 0 。

 

提示:

  • 1 <= nums.length <= 2 * 104
  • 1 <= m <= k <= nums.length
  • 1 <= nums[i] <= 109

解法

方法一:滑动窗口 + 哈希表

我们可以遍历数组 $nums$,维护一个大小为 $k$ 的窗口,用哈希表 $cnt$ 统计窗口中每个元素的出现次数,用变量 $s$ 统计窗口中所有元素的和。如果 $cnt$ 中不同元素的个数大于等于 $m$,那么我们就更新答案 $ans = \max(ans, s)$

遍历结束后,返回答案即可。

时间复杂度 $O(n)$,空间复杂度 $O(k)$。其中 $n$ 是数组的长度。

Python3

class Solution:
    def maxSum(self, nums: List[int], m: int, k: int) -> int:
        cnt = Counter(nums[:k])
        s = sum(nums[:k])
        ans = 0
        if len(cnt) >= m:
            ans = s
        for i in range(k, len(nums)):
            cnt[nums[i]] += 1
            cnt[nums[i - k]] -= 1
            s += nums[i] - nums[i - k]
            if cnt[nums[i - k]] == 0:
                cnt.pop(nums[i - k])
            if len(cnt) >= m:
                ans = max(ans, s)
        return ans

Java

class Solution {
    public long maxSum(List<Integer> nums, int m, int k) {
        Map<Integer, Integer> cnt = new HashMap<>();
        int n = nums.size();
        long s = 0;
        for (int i = 0; i < k; ++i) {
            cnt.merge(nums.get(i), 1, Integer::sum);
            s += nums.get(i);
        }
        long ans = 0;
        if (cnt.size() >= m) {
            ans = s;
        }
        for (int i = k; i < n; ++i) {
            cnt.merge(nums.get(i), 1, Integer::sum);
            if (cnt.merge(nums.get(i - k), -1, Integer::sum) == 0) {
                cnt.remove(nums.get(i - k));
            }
            s += nums.get(i) - nums.get(i - k);
            if (cnt.size() >= m) {
                ans = Math.max(ans, s);
            }
        }
        return ans;
    }
}

C++

class Solution {
public:
    long long maxSum(vector<int>& nums, int m, int k) {
        unordered_map<int, int> cnt;
        long long s = 0;
        int n = nums.size();
        for (int i = 0; i < k; ++i) {
            cnt[nums[i]]++;
            s += nums[i];
        }
        long long ans = cnt.size() >= m ? s : 0;
        for (int i = k; i < n; ++i) {
            cnt[nums[i]]++;
            if (--cnt[nums[i - k]] == 0) {
                cnt.erase(nums[i - k]);
            }
            s += nums[i] - nums[i - k];
            if (cnt.size() >= m) {
                ans = max(ans, s);
            }
        }
        return ans;
    }
};

Go

func maxSum(nums []int, m int, k int) int64 {
	cnt := map[int]int{}
	var s int64
	for _, x := range nums[:k] {
		cnt[x]++
		s += int64(x)
	}
	var ans int64
	if len(cnt) >= m {
		ans = s
	}
	for i := k; i < len(nums); i++ {
		cnt[nums[i]]++
		cnt[nums[i-k]]--
		if cnt[nums[i-k]] == 0 {
			delete(cnt, nums[i-k])
		}
		s += int64(nums[i]) - int64(nums[i-k])
		if len(cnt) >= m {
			ans = max(ans, s)
		}
	}
	return ans
}

func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

TypeScript

function maxSum(nums: number[], m: number, k: number): number {
    const n = nums.length;
    const cnt: Map<number, number> = new Map();
    let s = 0;
    for (let i = 0; i < k; ++i) {
        cnt.set(nums[i], (cnt.get(nums[i]) || 0) + 1);
        s += nums[i];
    }
    let ans = cnt.size >= m ? s : 0;
    for (let i = k; i < n; ++i) {
        cnt.set(nums[i], (cnt.get(nums[i]) || 0) + 1);
        cnt.set(nums[i - k], cnt.get(nums[i - k])! - 1);
        if (cnt.get(nums[i - k]) === 0) {
            cnt.delete(nums[i - k]);
        }
        s += nums[i] - nums[i - k];
        if (cnt.size >= m) {
            ans = Math.max(ans, s);
        }
    }
    return ans;
}

...