[LeetCode] 349. 两个数组的交集
1. 问题描述
给定两个数组 nums1 和 nums2 ,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的
提示:
1 <= nums1.length, nums2.length <= 10000 <= nums1[i], nums2[i] <= 1000
2. 实现思路
2.1 自己的思路
~~(一定要写出来啊喂)~
有点偏暴力的解法,HashSet有个作用是去重,那么先对两个数组去重,然后利用Contain方法找交集即可
/*
* @lc app=leetcode.cn id=349 lang=csharp
*
* [349] 两个数组的交集
*/
// @lc code=start
public class Solution {
public int[] Intersection(int[] nums1, int[] nums2)
{
var h1 = new HashSet<int>();
var h2 = new HashSet<int>();
var ans = new List<int>();
foreach (var i in nums1)
h1.Add(i);
foreach (var i in nums2)
h2.Add(i);
// 保证h1更短
if (h1.Count > h2.Count) (h1, h2) = (h2, h1);
foreach (var i in h1)
if (h2.Contains(i))
ans.Add(i);
return ans.ToArray();
}
}
// @lc code=end
由上一个题[LeetCode] 242.有效的字母异位词的经验,考虑过开一个数组来存,但是发现每个值的范围是0到1000,可能会有点浪费空间。
2.2 题解思路
- 使用数组来做哈希的题目,是因为题目都限制了数值的大小
- 而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费
- 好像leetcode原题是没有数值范围的,后面才加上去的,加上去后用数组空间效率更高
观察题目发现结果要求是去重的,那么可以用到set,在C#里的话,常用的是HashSet和SortedSet,前者使用散列法效率更高,后者使用红黑树
随想录给的思路如下,相比我之前的实现,可以少开一个HashSet,因为第二个数组直接比较就行其实差别不大(?)

C++:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
unordered_set<int> nums_set(nums1.begin(), nums1.end());
for (int num : nums2) {
// 发现nums2的元素 在nums_set里又出现过
if (nums_set.find(num) != nums_set.end()) {
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};
- 时间复杂度: O(n + m) m 是最后要把 set转成vector
- 空间复杂度: O(n)
C#:好家伙,给库函数大人跪了,原来还有IntersectWith方法
public int[] Intersection(int[] nums1, int[] nums2) {
if(nums1==null||nums1.Length==0||nums2==null||nums1.Length==0)
return new int[0]; //注意数组条件
HashSet<int> one = Insert(nums1);
HashSet<int> two = Insert(nums2);
one.IntersectWith(two);
return one.ToArray();
}
public HashSet<int> Insert(int[] nums){
HashSet<int> one = new HashSet<int>();
foreach(int num in nums){
one.Add(num);
}
return one;
}
2.3 优化(或者敲一遍题解?)
那么根据理解敲一遍~
/*
* @lc app=leetcode.cn id=349 lang=csharp
*
* [349] 两个数组的交集
*/
// @lc code=start
public class Solution
{
public int[] Intersection(int[] nums1, int[] nums2)
{
if (nums1.Length == 0 || nums2.Length == 0) return Array.Empty<int>();
var h1 = nums1.ToHashSet();
var h2 = nums2.ToHashSet();
h1.IntersectWith(h2);
return h1.ToArray();
}
}
// @lc code=end
原本想着防止重复造轮子,写个数组的扩展方法实现将数组转HashSet叭,结果智能感知直接跳出内置ToHashSet方法了……
关于这里的时间复杂度是怎么算的呢?
首先是将两个数组转为哈希表,分别是O(n)和O(m)
然后是求交集,是O(min(n, m))
然后加起来看低阶项:O(n) + O(m) + O(min(n, m))
在大 O 表示法中,我们只保留影响最大的项,并且忽略常数。min(n, m) 的增长速度绝对不会超过 n + m,所以它被低阶项吸收。
因此,最终的时间复杂度简写为:O(n + m)。
3. 补充知识と杂谈,总结
- 那么这里又涉及到了该不该用库函数的问题
个人感觉对于算法题考查的东西还是少用,但如果是烂熟于心的东西可以用
- 然后是算法题中要不要避免工程思维
因为个人相比算法来说,更喜欢架构设计,以前刚开始刷算法题的时候,动不动就新开一个类然后一套SOLID组合拳整上去。
但算法其实是针对一个类似原子模块的核心实现,不需要去过度设计,另外是防御性编程,这个倒是可以养成习惯写上去,基本的防NRE之类的

浙公网安备 33010602011771号