一、前言
今天是进入hash表的第二天,难度开始有点提升了,我也深入学习了一些以前并不太接触也不太重视的知识点,今天就接着这道题深入的讲一讲我的心得吧。题目很基础,但是我感觉解法也是比较多样的,当然最优解的方法卡哥已经给出了详细的解释,请各位uu自己看吧。
二、题目(力扣第349—两个数组的交集. - 力扣(LeetCode))
给定两个数组 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] 也是可通过的
三、题解
这个题卡哥的解答我先放在这里了(代码随想录)请各位uu写不出来或者想要看看更好的算法时自行去看吧,我重点说说我的思路。我个人认为其实向量或者说数组也是可以解决这道题的,而且也是比较好懂的,话不多说,直接上代码吧。
(1)数组解法
先是完整的代码如下:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int> vec1(1000);//定义两个向量(数组)来存放nums1、nums2的元素
vector<int> vec2(1000);
vector<int> vec;//用来存放最后的结果(也就是交集元素)
int len1=nums1.size();//得到nums1、nums2的长度
int len2=nums2.size();
for(int i=0;i<len1;i++){//将nums1中的元素存入vec1
vec1(nums1[i])++;
}
for(int i=0;i<len2;i++){//将nums2中的元素存入vec2
vec2(nums2[i])++;
}
for(int i=0;i<1000;i++){//求交集
if((vec1[i]!=0)&&(vec2[i]!=0)){//若vec1和vec2中有交集
vec.push_back(i);//使用push_back函数增加vec长度
}}
return vec;
}
接下来就详细讲讲这个代码:
这里的vec1和vec2,是直接定义了大小,默认初值为0,而vec并没有定义大小这与后面vec使用push_back函数来增加长度是对应的,否则的话力扣的编译是会报错的,因为你在声明vector容器的时候没有指定大小造成空指针。
vector<int> vec1(1000);
vector<int> vec2(1000);
vector<int> vec;
接下来是整个算法最重要的地方:
这里的思路有点像昨天的题目中的,将nums对应的数值按照位置存入vec中,比如,nums[0]=5,则存入vec数组时,vec[nums[0]]++=vec[5]++;意思就是在下标为5的位置的值+1;从vec来看就是5这个数字出现了一次。如果此时nums[1]=5,那么vec[nums[1]]++,此时vec[5]的值就变成2了,意思就是5这个数字出现了两次。因此我只要把nums1、nums2的元素存入vec1、vec2中变成相应位置及次数即可。
for(int i=0;i<len1;i++){//将nums1中的元素存入vec1
vec1(nums1[i])++;
}
for(int i=0;i<len2;i++){//将nums2中的元素存入vec2
vec2(nums2[i])++;
}
在同时比较vec1、vec2中相同位置是否为0,若不为0则说明两个数组中都出现过该元素(交集元素),则存入vec中即可。同时注意因为vec没有定义大小是可变长度的,因此要用push_back来增加长度。
for(int i=0;i<1000;i++){//求交集
if((vec1[i]!=0)&&(vec2[i]!=0)){//若vec1和vec2中有交集
vec.push_back(i);//使用push_back函数增加vec长度
}}
以上就是我使用数组作为hash表来解题的过程,若有uu不太明白的,可以私信我,我们一起讨论讨论。
(2)set解法
先上代码如下:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int>st1;//使用unordered_set来存入nums的元素
unordered_set<int>st2;
unordered_set<int>result;//存放交集元素
int len1=nums1.size();//得到两个nums的长度
int len2=nums2.size();
for(int i=0;i<len1;i++){//将nums元素存入set中
st1.insert(nums1[i]);
}
for(int i=0;i<len2;i++){
st2.insert(nums2[i]);
}
for(auto it:st2){//判断是否有交集元素,若有则存入result中
if(st1.find(it)!=st1.end()){
result.insert(it);
}
}
return vector<int>(result.begin(),result.end());//返回vector类型
}
这里使用set或者是unordered_set的最大的区别和优点是,set是具有互异性的,意思就是任何元素不能在set中重复出现,而且set对于这种分散、稀疏的数组存放元素的时间复杂度比使用vector要小,而set与unordered_set的区别是,set的底层是使用的红黑树,而unordered_set的底层是使用的hash表,而且set中的元素是有序的,而unordered_set是无序的是按照存入的顺序存放的。同时set对比vector的区别有:第一、set不能按照下标访问元素,即不能出现set[i]这样的;第二、set不能直接存入元素,因为它都不能set[i]当然就不能直接按下标存入元素了,而要使用insert函数来插入元素。
使用set的思路与数组的思路差不多,但是在寻找交集元素的时候会方便一点,我同时讲讲这里的代码吧。
这里相当于使用的一个迭代器来遍历st2中的元素是否在st1里面,使用find函数来寻找,若find不等于尾迭代器,则说明在前面的迭代器中找到了该元素,说明该元素在st1中,说明是交集元素,存入result中即可。(for(auto it :st2)这种遍历是很方便的相当于重新定义,同时好像是只有c++11可以用auto吧,请各位uu自行去找找相关资料)。
for(auto it:st2){//判断是否有交集元素,若有则存入result中
if(st1.find(it)!=st1.end()){//使用find函数,若不等于st1的尾迭代器,则说明在前面的迭代器中找到了该元素,就是该元素存在在st1中
result.insert(it);
}
}
四、后记
进入hash表这部分,我觉得应该多去尝试使用set、map、pair这些不太熟悉的容器,这样其实对于提高算法能力有巨大的飞跃和帮助,可以简单的就解决一些以前复杂的问题。此外各位uu如果发现有不对的地方请私信我,大家一起讨论、学习,互相进步。我们都有光明的未来!!!