一、引言
这是一道非常简单的题目,权当睡前的一点小练习,顺便看看他人的代码学点技巧了。
题目信息如下:
Given two arrays, write a funtion to compute their intersection.
Example:
Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2].Note:
1.Each element in the result must be unique.
2.The result can be in any order.
简单翻译一下:
给定两个数组,写一个方法计算这两个数组的交集
举例:
nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2]注意:
1.结果集合中的每个元素都必须是唯一的
2.结果可以是任何的顺序
其实了解 C++ 的人,看到这道题,第一个冒出来的东西就应该是:
std::set
当我们需要查找指定的值是否在指定集合中出现的时候,使用 std::set
往往是最佳的选择。
二、睡前的惬意:std::set 的使用
这道题逻辑非常简单,但是我们要注意以下几点:
其一,我们需要知道输出的结果中的每个元素都是唯一的。这一点也就意味着,我们需要对 nums1 和 nums2 进行去重处理
其二,我们需要拿到一个数组中的所有元素到另一个数组中去进行查找是否存在的计算。这里很明显就会考虑到
std::set
的使用
根据上述的分析,可以写出代码如下:
// my solution use two set , runtime = 13 ms
class Solution1 {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
set<int> set1(nums1.begin(), nums1.end());
set<int> set2(nums2.begin(), nums2.end());
vector<int> result;
for (auto i : set1)
if (set2.find(i) != set2.end()) result.push_back(i);
return result;
}
};
这里简要介绍下:
首先声明了两个
std::set
对象,来保存 nums1 和 nums2 中出现的所有元素,并且因为是std::set
,所以达到了自动去重的目的然后拿 set1 中的所有元素去查找 set2 中是否出现,如果出现了则表示产生了共同元素并压入返回数组中去
这道题的代码逻辑非常简单,我思考了下,也确实没有什么优化点了(C++ Primer 5h 提倡 C++11 的用法是能用 STL 就用 STL),所以说接下来让我们看看其他人的答案权当观光旅游吧 : )
三、观看他人的解法:阅读代码也是一种乐趣
点开 Discuss
栏目,映入眼帘的是这个方法:
C++ sort and two pointers
也就是说使用了排序和两个指针的方法,那么想必就是先进行排序,然后两个数组两个指针进行对比操作的方法了:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size(), m = nums2.size();
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
int i = 0, j = 0;
vector<int> res;
while (i < n && j < m) {
if (nums1[i] < nums2[j]) i++;
else if (nums1[i] > nums2[j]) j++;
else {
if (res.empty() || nums1[i] != res[res.size() - 1]) res.push_back(nums1[i]);
i++; j++;
}
}
return res;
}
看到了代码,果不其然,简要分析下他的代码逻辑:
首先,将 nums1 和 nums2 进行排序,此时两个数组都是由小到大进行排列
然后,我们将 i 指向 nums1 的第一个位置,j 指向 nums2 的第一个位置,一直遍历直到找到 i 和 j 指向的值相等的位置时停下来
再然后,我们已经让 i 和 j 分别指向了 nums1 和 nums2 中相等的元素了,此时我们就可以压入返回数组 res 了,但是此时我们还需要甄别此元素是否已经在 res 中存在了,因为 res 默认也是从小到大排序的,因此我们只需要比较 res 最右边的一个元素即可
最后,我们一直遍历,直到 i 或者 j 指向了数组末尾
这个方法虽然看上去比之我的方法复杂了点,但是 runtime 非常好看,只有区区的 6ms(刚才我的方法的 runtime = 13 ms)。
再来看一个答案吧,总觉得有点不够尽兴:
8ms concise C++ using unordered_set
嗯,看标题使用了 unordered_set,那么确实, unordered_set 的效率确实要比 set 高:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> m(nums1.begin(), nums1.end());
vector<int> res;
for (auto a : nums2)
if (m.count(a)) {
res.push_back(a);
m.erase(a);
}
return res;
}
};
这里简要分析下他的代码逻辑:
首先,将 nums1 初始化了一个 unordered_set
然后,遍历 nums2 中的所有元素,拿着 nums2 的元素去查找 unordered_set 中是否存在,并且与众不同的是,作者为了解决重复的问题,压入了存在的元素后,直接在 unordered_set 中删除了该元素(非常秒!)
最后,直到遍历结束,返回结果数组
这个方法在我的笔记本上实测 runtime 为 6ms,还是不错了,作者能够想到为了去重,去删除 unordered_set 中的元素,非常秒。
四、总结
有些人觉得 LeetCode 上面的题就应该是非常难的,其实我觉得并不是。
LeetCode 作为一个题库,需要的是面面俱到,既适合菜鸟提升自己(比如我 T_T),又适合高手来证明自己(比如那种一天刷 70 多道题的大神)。作为菜鸟的我,追求的并非是那几行能够正确运行并且 Accept 的代码,而是思考探索的过程,或者说是追求代码极致简洁和优雅的爱好。
总之,不管各种原因林林总总,我都和大多数人一样,刷着 LeetCode。
爱着 LeetCode,因为我相信上面有许许多多真正喜爱着编程的人。
I Love LeetCode ^_^