LeetCode 2215. 找出两数组的不同
题目描述


题意分析
返回两个列表:第一个包含只在
nums1出现、完全不在nums2出现的不同数值;第二个方向相反。每个列表内部去重,元素顺序不限。比较的是值是否出现,不是两个数组同一下标是否相等,也不比较次数多少。一个值只要在两边都出现,就不属于任何一侧的结果;即使某个结果为空,返回结构也必须保留两个列表。
解法:分别计算两个集合的差集
核心思路
[!blue]
题目同时需要“去重”和“判断另一边有没有”,分别将两个数组放入哈希集合即可完成这两件事。集合只保留不同值,重复出现次数不会影响后续判断。
遍历
set1时,只把不存在于set2的值加入第一列表。每个值在set1中最多遍历一次,保证输出不重复;再以相反方向遍历set2,得到第二列表。两次判断都需要读取对方原本完整的集合。因此代码始终保留两个集合,不在第一轮删除共同元素,否则第二轮可能把原本共有的值误认为只属于第二边。数组本身不需要排序或修改,负数也能直接作为集合键。
解题步骤
- 分别将两个数组中的所有值加入
set1和set2。- 遍历去重后的
set1,未被set2包含的值加入only1。- 遍历完整
set2,未被set1包含的值加入only2。- 按
[only1, only2]的固定方向返回,即使某个列表为空也保留它。
代码实现
class Solution {
public List<List<Integer>> findDifference(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<>();
for (int num : nums1) {
// 集合天生去重,负数也能直接当键,不需要下标偏移。
set1.add(num);
}
Set<Integer> set2 = new HashSet<>();
for (int num : nums2) {
set2.add(num);
}
List<Integer> only1 = new ArrayList<>();
for (int num : set1) {
// 方向一:遍历已去重的 set1,查 set2 是均摊 O(1)。
if (!set2.contains(num)) {
only1.add(num);
}
}
List<Integer> only2 = new ArrayList<>();
for (int num : set2) {
// 方向二与方向一完全对称;全程没有修改过集合,这里读到的 set1 是完整的。
if (!set1.contains(num)) {
only2.add(num);
}
}
List<List<Integer>> answer = new ArrayList<>();
// 即使某个列表为空也必须占位,返回值长度恒为 2。
answer.add(only1);
answer.add(only2);
return answer;
}
}
func findDifference(nums1 []int, nums2 []int) [][]int {
set1 := make(map[int]struct{}, len(nums1))
for _, num := range nums1 {
// struct{} 不占空间,这里只用键来表示集合成员。
set1[num] = struct{}{}
}
set2 := make(map[int]struct{}, len(nums2))
for _, num := range nums2 {
set2[num] = struct{}{}
}
// 初始化为空切片而非 nil,否则空结果会被序列化成 null。
only1 := []int{}
for num := range set1 {
// 方向一:查 set2,双值写法可以区分「键不存在」。
if _, ok := set2[num]; !ok {
only1 = append(only1, num)
}
}
only2 := []int{}
for num := range set2 {
// 方向二与方向一完全对称,只是两个集合角色互换。
if _, ok := set1[num]; !ok {
only2 = append(only2, num)
}
}
return [][]int{
only1,
only2,
}
}
复杂度分析
- 时间复杂度:期望 $O(m+n)$,建集合扫描全部输入,再各扫描一次不同值,哈希查询平均为常数。
- 空间复杂度:$O(m+n)$,两组集合与输出总规模不超过输入数量级。
关键点总结
[!green]
- 将出现次数压缩成集合成员关系,恰好满足去重与存在性判断。
- 两个差集的方向不同,不能把它们合并为一个集合。
- 遍历集合而非原数组,天然避免输出重复值。
- 查询期间保留完整原集合,避免两个方向的计算互相干扰。
易错点总结
[!yellow]
- 按同一下标比较两个数组,无法判断一个值是否在对方其他位置出现。
- 直接遍历原数组输出且不去重,同一个独有值可能重复加入。
- 认为出现次数更多的一侧应保留共同值,本题只关心是否存在。
- 第一轮删除共同元素后,用这个残缺集合计算第二方向,会把共同值错误输出。
- 空结果列表不占位,或交换两个列表的位置,改变题目要求的返回结构。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 349. 两个数组的交集 | 简单 | 同样先按集合处理重复值,原题求交集,本题分别求两个方向的差集。 |
| 350. 两个数组的交集 II | 简单 | 原题交集保留重数,本题只关心是否出现并要求去重。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!