让我们先来看看题目😋
3690. 拆分合并数组


这道题目非常有意思,我们可以看道数据范围非常的小啊,所以我们可以直接用暴力就可以解决了,详细题解请看灵神的题解。
因为本人才刚刚学习Java,对于很多知识点都不了解,所以写这篇博客来梳理一下这道题用到的基础知识。我们先来看看灵神的代码
class Solution {
public int minSplitMerge(int[] nums1, int[] nums2) {
int n = nums1.length;
List<Integer> nums2List = toList(nums2);
Set<List<Integer>> vis = new HashSet<>();
vis.add(toList(nums1));
List<List<Integer>> q = List.of(toList(nums1));
for (int ans = 0; ; ans++) {
List<List<Integer>> tmp = q;
q = new ArrayList<>();
for (List<Integer> a : tmp) {
if (a.equals(nums2List)) {
return ans;
}
for (int l = 0; l < n; l++) {
for (int r = l + 1; r <= n; r++) {
List<Integer> sub = a.subList(l, r);
List<Integer> b = new ArrayList<>(a);
b.subList(l, r).clear(); // 从 b 中移除 sub
for (int i = 0; i <= b.size(); i++) {
List<Integer> c = new ArrayList<>(b);
c.addAll(i, sub);
if (vis.add(c)) { // c 不在 vis 中
q.add(c);
}
}
}
}
}
}
}
private List<Integer> toList(int[] nums) {
return Arrays.stream(nums).boxed().collect(Collectors.toList());
}
}
作者:灵茶山艾府
链接:https://leetcode.cn/problems/split-and-merge-array-transformation/solutions/3787914/bfspythonjavacgo-by-endlesscheng-86ya/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
知识点1
先来看看下面这个方法
private List<Integer> toList(int[] nums) {
return Arrays.stream(nums).boxed().collect(Collectors.toList());
}
🔍 逐层解析
1. Arrays.stream(nums)
- 作用:将int数组转换为
IntStream - 输入:
int[] nums(原始类型数组) - 输出:
IntStream(专门处理int的流)
2. .boxed()
- 核心转换:将
IntStream中的int元素装箱为Integer - 为什么需要:Java泛型不支持原始类型,List只能存储对象
- 转换前:
int→ 转换后:Integer
3. .collect(Collectors.toList())
- 终端操作:将流中的元素收集到List中
- Collectors.toList():返回一个收集器,将元素累积到新List
知识点2
📝 代码解析
Set<List<Integer>> vis = new HashSet<>();
vis.add(toList(nums1));
List<List<Integer>> q = List.of(toList(nums1));
🔍 逐行详解
1. Set<List<Integer>> vis = new HashSet<>();
知识点:泛型集合 + 钻石运算符
- Set接口:不允许重复元素的集合
- List作为元素:存储整数列表的集合
- HashSet实现:基于哈希表的Set实现,O(1)时间复杂度查找
- 钻石运算符:编译器自动推断泛型类型
2. vis.add(toList(nums1));
知识点:集合操作 + 方法调用链
// 分解步骤:
List<Integer> firstList = toList(nums1); // 数组转List
boolean added = vis.add(firstList); // 添加到Set,返回是否成功添加
3. List<List<Integer>> q = List.of(toList(nums1));
知识点:工厂方法 + 不可变集合
- List.of():Java 9+ 的工厂方法,创建不可变列表
- 嵌套泛型:
List<List<Integer>>- 存储List的List - 单元素列表:创建只包含一个元素的不可变列表
知识点3
📝 代码解析
List<Integer> sub = a.subList(l, r);
List<Integer> b = new ArrayList<>(a);
b.subList(l, r).clear(); // 从 b 中移除
🔍 逐行详解
1. List<Integer> sub = a.subList(l, r);
知识点:视图切片 + 区间操作
- subList(l, r):返回原列表从索引l到r-1的视图
- 不是拷贝:
sub与a共享底层数据,修改会相互影响 - 前闭后开:
[l, r)包含l,不包含r - 示例:
a = [1,2,3,4,5],sublist(1,4) = [2,3,4]
2. List<Integer> b = new ArrayList<>(a);
知识点:深拷贝 + 构造函数复制
- 新建独立列表:
b是a的完整拷贝,两者独立 - 内存开销:O(n)空间复杂度
- 修改隔离:对
b的修改不会影响原列表a
3. b.subList(l, r).clear();
知识点:视图操作 + 批量删除
- 链式调用:
subList().clear()直接在原列表上操作 - 高效删除:一次性删除区间元素,比循环remove高效
- 底层实现:调用
removeRange(l, r)方法
知识点4
📝 代码解析
List<Integer> c = new ArrayList<>(b);
c.addAll(i, sub);
if (vis.add(c)) { // c 不在 vis 中
q.add(c);
}
🔍 逐行详解
1. List<Integer> c = new ArrayList<>(b);
知识点:防御性拷贝 + 状态隔离
- 创建副本:基于列表
b创建全新的ArrayList - 状态独立:对
c的修改不会影响原列表b - 内存代价:O(n)空间复杂度,但保证数据安全
2. c.addAll(i, sub);
知识点:列表插入 + 索引操作
- 批量插入:将
sub列表的所有元素插入到位置i - 索引位置:
i必须在[0, c.size()]范围内 - 元素移动:插入点后的元素自动后移
3. if (vis.add(c)) { q.add(c); }
知识点:集合判重 + 条件添加
- vis.add©:尝试将列表
c添加到HashSet- 返回
true:元素不存在,成功添加 - 返回
false:元素已存在,添加失败
- 返回
- 条件入队:只有新状态才加入处理队列
⚡ 完整流程示例
// 初始状态
List<Integer> b = Arrays.asList(1, 2, 3);
List<Integer> sub = Arrays.asList(7, 8);
Set<List<Integer>> vis = new HashSet<>();
Queue<List<Integer>> q = new LinkedList<>();
// 执行过程
List<Integer> c = new ArrayList<>(b); // c = [1, 2, 3]
c.addAll(1, sub); // c = [1, 7, 8, 2, 3]
if (vis.add(c)) { // 如果[1,7,8,2,3]不在vis中
q.add(c); // 加入待处理队列
}
🎯 核心知识点
HashSet判重机制
// List的equals和hashCode决定重复判断
List<Integer> list1 = Arrays.asList(1, 2, 3);
List<Integer> list2 = Arrays.asList(1, 2, 3);
vis.add(list1); // 返回true,成功添加
vis.add(list2); // 返回false,内容相同,视为重复
BFS/状态搜索模式
// 典型的状态空间搜索框架
while (!q.isEmpty()) {
List<Integer> current = q.poll();
for (每个可能的操作) {
List<Integer> nextState = new ArrayList<>(current); // 创建副本
// 对nextState进行修改...
if (visited.add(nextState)) { // 新状态检测
q.add(nextState); // 加入待处理
}
}
}
性能考虑
// 优化思路:使用更高效的数据结构
Set<String> vis = new HashSet<>(); // 存储序列化字符串
// 将List转为String存储,减少内存占用
String state = c.toString();
if (vis.add(state)) {
q.add(new ArrayList<>(c));
}
关键点:这套模式是图遍历/状态搜索算法的核心,确保不重复处理相同状态!
感谢您的观看,期待关注。






