|
| 1 | +# [3013. 将数组分成最小总代价的子数组 II](https://leetcode.cn/problems/divide-an-array-into-subarrays-with-minimum-cost-ii/description/) |
| 2 | + |
| 3 | +> **日期**:2026-01-31 |
| 4 | +> **所用时间**:5min |
| 5 | +> **知识点**:滑动窗口、有序集合 |
| 6 | +
|
| 7 | +## 1. 题目描述 |
| 8 | + |
| 9 | +给你一个长度为 n 的 0 索引整数数组 `nums`,以及两个正整数 `k` 和 `dist`。 |
| 10 | + |
| 11 | +每个子数组的**代价**为该子数组的第一个元素。例如,`[3,4,1]` 的代价是 3,`[10,2,3]` 的代价是 10。 |
| 12 | + |
| 13 | +你需要将 `nums` 分成 `k` 个**互不相交**的连续子数组,且满足:**第二段子数组的起始下标**与**第 k 段子数组的起始下标**之差不超过 `dist`。换句话说,若将数组划分为 `[0, i₁), [i₁, i₂), ..., [i_{k-1}, n)`,则需满足 `i_{k-1} - i₁ ≤ dist`。 |
| 14 | + |
| 15 | +请你返回这些子数组代价的**最小可能总和**。 |
| 16 | + |
| 17 | +**示例 1:** |
| 18 | + |
| 19 | +输入:nums = [1,2,3,12], k = 3, dist = 1 |
| 20 | + |
| 21 | +输出:6 |
| 22 | + |
| 23 | +解释:需选 2 个起点(k-1=2),窗口大小为 2(dist+1)。从 nums[1:3]=[2,3] 中取最小的 2 个,和为 2+3=5,总代价为 nums[0]+5=6。 |
| 24 | + |
| 25 | +**示例 2:** |
| 26 | + |
| 27 | +输入:nums = [10,1,2,2,2,10], k = 3, dist = 3 |
| 28 | + |
| 29 | +输出:12 |
| 30 | + |
| 31 | +解释:窗口大小为 4,从每个合法窗口中选 2 个最小元素,取最小和加上 10。 |
| 32 | + |
| 33 | +**约束:** 3 ≤ n ≤ 10⁵,3 ≤ k ≤ n,k - 2 ≤ dist ≤ n - 2 |
| 34 | + |
| 35 | +## 2. 解题算法 |
| 36 | + |
| 37 | +题意等价于:第一段一定从下标 0 开始(代价为 `nums[0]`),需从后续位置中选出 `k-1` 个作为第 2~k 段的起点,且这 `k-1` 个起点的下标必须在某个长度为 `dist+1` 的窗口内,最小化 `nums[0]` 加上这 `k-1` 个起点对应元素的和。 |
| 38 | + |
| 39 | +**算法思路:** 用**滑动窗口**枚举所有合法的 `dist+1` 长度区间,对每个窗口维护其中最小的 `k-1` 个元素的和,取全局最小值。使用 `SortedList`(有序列表)维护窗口内元素,便于增删和取前 k-1 小。 |
| 40 | + |
| 41 | +**步骤:** |
| 42 | + |
| 43 | +1. 初始窗口为 `nums[1 : dist+2]`,用 `SortedList` 维护,计算前 `k-1` 小的和 `s`。 |
| 44 | +2. 从左向右滑动窗口:每次移除 `nums[i-dist-1]`,加入 `nums[i]`,并更新前 k-1 小的和。 |
| 45 | +3. 若新加入元素小于当前第 k-1 小,则更新 `s`;若移除元素曾是前 k-1 小之一,也需更新 `s`。 |
| 46 | +4. 对所有窗口取 `s` 的最小值,加上 `nums[0]` 即为答案。 |
| 47 | + |
| 48 | +**复杂度分析:** |
| 49 | + |
| 50 | +- 时间复杂度:O(n log(dist)),每次 `add`/`remove` 为 O(log(dist)),共 O(n) 次。 |
| 51 | +- 空间复杂度:O(dist),`SortedList` 最多存 `dist+1` 个元素。 |
| 52 | + |
| 53 | +**Python3** |
| 54 | + |
| 55 | +```python |
| 56 | +class Solution: |
| 57 | + def minimumCost(self, nums: List[int], k: int, dist: int) -> int: |
| 58 | + k -= 1 |
| 59 | + sl = SortedList(nums[1: dist + 2]) |
| 60 | + ans = s = sum(sl[:k]) |
| 61 | + |
| 62 | + for i in range(dist + 2, len(nums)): |
| 63 | + if nums[i] < sl[k - 1]: |
| 64 | + s += nums[i] - sl[k - 1] |
| 65 | + sl.add(nums[i]) |
| 66 | + sl.remove(nums[i - dist - 1]) |
| 67 | + if nums[i - dist - 1] < sl[k - 1]: |
| 68 | + s += sl[k - 1] - nums[i - dist - 1] |
| 69 | + ans = min(ans, s) |
| 70 | + return ans + nums[0] |
| 71 | +``` |
0 commit comments