目录
题干
给定两个数组 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] 也是可通过的
数据结构(set)
这道题也是用到了哈希表的思想,不过这次使用的数据结构是set
set是C++标准模板库(STL)中提供的一种容器,它实现了数学上的集合概念,即集合中的元素是唯一的,每个元素在集合中只出现一次。set的内部实现通常是基于红黑树,这是一种自平衡的二叉查找树,可以保证元素的有序性和高效的查找、插入和删除操作。
以下是set的一些主要特点:
- 唯一性:set中不允许有重复的元素,每个元素都是唯一的。
- 有序性:set中的元素会根据元素的值自动排序,保持一定的顺序。
- 高效性:由于内部实现是红黑树,set提供了对数级别的查找、插入和删除操作。
- 支持的操作:set支持一系列的操作,如判断元素是否存在、插入新元素、删除元素等。
总的来说,set是一个非常有用的工具,特别是在需要快速检索元素的情况下。
由于题目中没有要求元素的值有顺序,所以这里我们使用的是无序set,即unordered_set
与set不同,unordered_set内部实现是基于哈希表的,而不是红黑树。因此,它不保证元素的顺序,并且元素的存储位置是根据元素的哈希值决定的。
以下是unordered_set的一些主要特点:
- 唯一性:unordered_set中不允许有重复的元素,每个元素都是唯一的。
- 无序性:由于使用哈希表进行存储,unordered_set中的元素没有固定的顺序。
- 高效性:由于哈希表的查找、插入和删除操作的平均时间复杂度为常数级别O(1),所以unordered_set提供了高效的性能。
- 支持的操作:unordered_set支持一系列的操作,如判断元素是否存在、插入新元素、删除元素等。
总的来说,unordered_set是一种非常快速且高效的数据结构,适用于需要快速检索元素的场景,但不需要元素有序的情况。
以下是本题中要使用到的unordered_set的用法:
-
创建unordered_set对象:可以使用以下方式创建一个空的unordered_set对象:
std::unordered_set<int> mySet;
-
插入元素:使用insert()函数将元素插入到unordered_set中:
mySet.insert(42);
-
查找元素:可以使用find()函数来查找元素是否存在于unordered_set中:
if (mySet.find(42) != mySet.end()) { // 元素存在 } else { // 元素不存在 }
如果存在,返回指向该元素的迭代器;如果不存在,返回指向集合末尾的迭代器。
解题思路
整体的思路是将数组1的所有元素放到以set为数据结构的哈希表中,然后遍历数组2中的元素,与哈希表中的key对照,如果有相等的值就把该值放入结果set中。
完整代码如下:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set;
unordered_set<int> num_set(nums1.begin(),nums1.end());
for(int num : nums2){
if(num_set.find(num) != num_set.end())
result_set.insert(num);
}
return vector<int> (result_set.begin(),result_set.end());
}
};
这一道题也牵涉到了许多c++的用法
unordered_set<int> nums_set(nums1.begin(), nums1.end());
这段代码创建了一个名为nums_set的无序集合,并将nums1向量中的元素插入到该集合中。
(nums1.begin(), nums1.end())
是一个范围表达式,它指定了要插入到集合中的元素范围。这里使用了nums1向量的起始迭代器和结束迭代器来定义范围。
for (int num : nums2)
这段代码是一个基于范围的for循环,用于遍历nums2向量中的每个元素。
(int num : nums2)
是范围表达式,它定义了要遍历的元素和容器。这里使用了C++11引入的范围for循环语法。
int num
是循环变量,表示每次迭代时从nums2中取出的元素。
nums2
是要遍历的容器,即包含整数元素的向量。
因此,这段代码的作用是在每次迭代中,将nums2向量中的一个元素赋值给变量num,然后执行循环体内的代码。
return vector<int> (result_set.begin(),result_set.end());
这段代码的作用是将一个集合(result_set)转换为一个整数向量(vector)。
result_set.begin()
返回指向集合中第一个元素的迭代器。
result_set.end()
返回指向集合中最后一个元素之后的迭代器。
vector<int>(result_set.begin(), result_set.end())
使用这两个迭代器作为参数,创建一个新的整数向量,并将集合中的元素复制到该向量中。
因此,这段代码的作用是将集合中的元素复制到一个新的整数向量中,并返回该向量。
数据结构(数组)
本题后面力扣改了题目描述和后台测试数据,增添了数值范围:
- 1 <= nums1.length, nums2.length <= 1000
- 0 <= nums1[i], nums2[i] <= 1000
所以我们也可以使用数组来做哈希表, 因为数组都是 1000以内的。
这里提一句数组相比于set的优点,因为直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的,因此在遇到数据量较大的情况下,如果能用数组肯定是会节约不少时间的。
以下是完整代码:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; /
int hash[1005] = {0};
for (int num : nums1) {
hash[num] = 1;
}
for (int num : nums2) {
if (hash[num] == 1) {
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};