DeepSeek LeetCode 2963. 统计好分割方案的数目 Java实现
好的,这道题我们先理解一下题意,然后再给出 Java 实现。
题目理解
LeetCode 2963. 统计好分割方案的数目
好分割的定义:
将数组分割成若干个连续的非空子数组,使得每个数字在所有的子数组中最多出现一次。
换句话说,对于一个数字,它在原数组中出现的所有位置,必须属于同一个子数组,不能跨两个不同的子数组。
---
思路
1. 记录每个数字的最后出现位置
· 遍历一次数组,用 lastPos[x] 记录数字 x 最后一次出现的下标。
2. 贪心扫描划分点
· 从左到右遍历数组,维护当前段需要覆盖到的最大右边界 currEnd。
· 当遍历到下标 i,更新 currEnd = max(currEnd, lastPos[nums[i]])。
· 如果 i == currEnd,说明当前位置可以作为一个分割点(这个段的最后一个位置)。
· 每找到一个分割点,可能的分段方式就会翻倍(因为可以在这些分割点处选择切或不切)。
3. 计算方案数
· 如果有 k 个可分割的位置(不包括数组末尾),那么方案数为 2^(k)。
· 注意:整个数组必须作为一个完整的分割,所以 k 指的是中间可切开的位置数。
· 用快速幂或逐次乘 2 来避免溢出。
---
举例
示例:
nums = [1, 1, 2, 2, 3, 3]
· lastPos:
1 → 1
2 → 3
3 → 5
遍历:
· i=0, currEnd = lastPos[1] = 1 → i != currEnd
· i=1, currEnd = max(1, lastPos[1]=1) = 1, i == currEnd → 切分点 +1
· i=2, currEnd = max(1, lastPos[2]=3) = 3
· i=3, currEnd = max(3, lastPos[2]=3) = 3, i == currEnd → 切分点 +1
· i=4, currEnd = max(3, lastPos[3]=5) = 5
· i=5, currEnd = max(5, lastPos[3]=5) = 5, i == currEnd → 切分点 +1
切分点位置:1, 3, 5(3个)
分段数 = 2^3 = 8
---
Java 实现
```java
class Solution {
public int numberOfGoodPartitions(int[] nums) {
Map<Integer, Integer> lastPos = new HashMap<>();
int n = nums.length;
// 记录每个数字最后出现的位置
for (int i = 0; i < n; i++) {
lastPos.put(nums[i], i);
}
int segments = 0;
int currEnd = 0;
for (int i = 0; i < n; i++) {
currEnd = Math.max(currEnd, lastPos.get(nums[i]));
if (i == currEnd) {
segments++;
}
}
// 有 segments 段,中间有 segments-1 个切割点,每个切割点可以切或不切
// 所以总方案数 = 2^(segments-1)
long ans = 1;
int MOD = 1_000_000_007;
for (int i = 1; i < segments; i++) {
ans = (ans * 2) % MOD;
}
return (int) ans;
}
}
```
---
复杂度分析
· 时间复杂度:O(n)
· 空间复杂度:O(n),存储每个数字最后出现的位置
---
总结
核心是找到所有必须合并在一起形成的“块”,块的数量决定了中间有多少个可选的切割点,每个切割点独立决定切或不切,因此方案数为 2^(块数-1)。
更多推荐





所有评论(0)