Skip to content

Commit 253bf66

Browse files
committed
feat: 20260202 check in
1 parent a10754b commit 253bf66

2 files changed

Lines changed: 78 additions & 3 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
```

leetcode/4-每日一题/3180. 执行操作可获得的最大总奖励 I.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# [3180. 执行操作可获得的最大总奖励 I](https://leetcode.cn/problems/maximum-total-reward-using-operations-i/description/)
22

3-
> **作者**弘树
4-
> **日期**2024-10-25
5-
> **所用时间**16min
3+
> **日期**2024-10-25、2026-02-02
4+
> **所用时间**16min
5+
> **知识点**动态规划
66
77
## 1. 动态规划
88

@@ -31,6 +31,8 @@ $$
3131

3232
由于每一次状态更新只用到上一层的状态,所以可以使用滚动数据进行空间复杂度的优化。
3333

34+
复杂度分析:
35+
3436
- 时间复杂度: $O(n \times U)$,$n$ 为数组 $rewardValues$ 的长度,$U$ 为数组 $rewardValues$ 中的最大值的两倍
3537
- 空间复杂度: $O(U)$
3638

@@ -43,10 +45,12 @@ class Solution:
4345
m = rewardValues[-1] << 1
4446
f = [False] * m
4547
f[0] = True
48+
4649
for reward in rewardValues:
4750
for j in range(m):
4851
if 0 <= j - reward < reward:
4952
f[j] |= f[j - reward]
53+
5054
ans = m - 1
5155
while not f[ans]:
5256
ans -= 1

0 commit comments

Comments
 (0)