LeetCode 2841. 幾乎唯一子陣列的最大和(滑動視窗圖解)
2841. 幾乎唯一子陣列的最大和
題目描述
給你一個整數陣列 nums 和兩個正整數 m 和 k。
請你回傳 nums 中長度為 k 的幾乎唯一子陣列的最大和,如果不存在幾乎唯一子陣列,請回傳 0。
如果 nums 的一個子陣列有至少 m 個互不相同的元素,我們稱它是幾乎唯一子陣列。
子陣列指的是一個陣列中一段連續非空的元素序列。
範例 1
1 | |
範例 2
1 | |
範例 3
1 | |
限制
1 <= nums.length <= 2 * 10^41 <= m <= k <= nums.length1 <= nums[i] <= 10^9
本文題解思路與程式碼整理自 LeetCode 題解作者「灵茶山艾府」,題解連結。圖解為自行補充。
前置知識:滑動視窗
視窗是陣列中由起訖索引定義的一段連續元素。定長視窗每次向右滑一格,就是少一個最左邊的元素、多一個新進來的元素,所以視窗內的總和可以 O(1) 更新,不必每次重算。
思路
題目要的是「長度固定為 k 的視窗,且視窗內不同元素個數 ≥ m,求最大和」,需要同時維護兩個量:
- 視窗總和
s:進來加、出去減。 - 視窗內不同元素的個數:這是難點。
怎麼統計一個陣列有多少不同元素?全丟進雜湊集合,集合大小就是答案。但在滑動視窗裡,元素 x 離開視窗時,要不要從集合刪掉?
x是視窗中唯一的一個:刪。- 視窗裡還有別的
x:不能刪。
要知道 x 在視窗裡還剩幾個,就得記錄出現次數,所以改用雜湊表:key 是元素值,value 是它在視窗中的出現次數。
- 入:
x = nums[i]進入視窗,s += x,cnt[x]++。若i < k - 1視窗還沒滿,繼續。 - 更新:若
cnt.size() >= m,用s更新答案的最大值。 - 出:
x = nums[i - k + 1]離開視窗,s -= x,cnt[x]--。若減完是 0,要把x從雜湊表刪除,否則cnt.size()會把出現 0 次的元素也算進去。
圖解(可互動)
使用範例 1:nums = [2,6,7,3,1,7],m = 3,k = 4。可以看到雜湊表內容如何隨視窗變化,以及最後一個視窗裡 7 的次數變成 2,但不同元素只有 3 個。
nums = [2,6,7,3,1,7],m = 3,k = 4
視窗內
入 = 新進入
出 = 剛離開
視窗總和 s0
不同元素 cnt.size()0
目前最大值 ans0
解法(灵茶山艾府)
1 | |
幾個細節:
s用long:k最大 2 * 10^4、元素最大 10^9,總和會超過int。cnt.merge(x, 1, Integer::sum)等價於cnt[x]++,key 不存在時直接放 1。- 離開視窗時一定要在次數歸零時
remove,這是這題最容易出錯的地方。
複雜度分析
- 時間複雜度:O(n),其中 n 是
nums的長度,每個元素進出視窗各一次。 - 空間複雜度:O(k),雜湊表大小不會超過視窗長度 k。
LeetCode 2841. 幾乎唯一子陣列的最大和(滑動視窗圖解)
https://shengshengyang.github.io/2026/10/19/leetcode-2841-max-sum-almost-unique-subarray/