Given two arrays, write a function to compute their intersection.(给定两个数组,计算它们的交叉元素)
Example:
Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2].
Note:
● Each element in the result must be unique.(在结果中每个元素都是唯一的)
● The result can be in any order.(结果序列任意)
1.个人分析
(1)首先从最直观简单的方法入手,同时从头遍历两个数组,这需要两个for循环来实现,比如,数组a1的第一个元素需要与数组a2中的每个元素进行比较,直到找到相同元素或者遍历到尾部,关键是如何实现返回的数组不包含重复的元素。
(2)去重的思路有两种,一个是在遍历过程中就保证放入元素是唯一的交叉元素,另一个是在遍历完成后再对交叉元素数组进行去重操作。
2.个人解法
(1)
vector<int> intersection(vector<int>& nums1, vector<int>& nums2)
{
vector<int>nums3;
for (int i=0; i < nums1.size(); ++i)
{
for (int j=0; j < nums2.size(); ++j)
{
if(nums1[i] == nums2[j])
{
bool bExist = false;
for(int k=0; k<nums3.size(); ++k)
{
if(nums1[i] == nums3[k])
{
bExist = true;
break;
}
}
if(!bExist)
{
nums3.push_back(nums1[i]);
}
break;
}
}
}
return nums3;
}
这种方法时间复杂度为O(n^3),空间复杂度为O(1),解决方法虽然直接简单,但时间复杂度让人无法容忍,在实际中肯定行不通的。
(2)
vector<int> intersection2(vector<int>& nums1, vector<int>& nums2)
{
vector<int>nums3;
for (int i=0; i < nums1.size(); ++i)
{
for (int j=0; j < nums2.size(); ++j)
{
if(nums1[i] == nums2[j])
{
nums3.push_back(nums1[i]);
break;
}
}
}
vector<int>tmp;
if(!nums3.empty())
tmp.push_back(nums3[0]);
for (int i=0; i<nums3.size(); ++i)
{
bool bExist = false;
for(int j=0; j<tmp.size(); ++j)
{
if(nums3[i] == tmp[j])
{
bExist = true;
break;
}
}
if(!bExist)
tmp.push_back(nums3[i]);
}
return tmp;
}
该方法的时间复杂度为O(n^2),空间复杂度为O(n),相对第一种方法是用空间换时间,但这种方法依然不会是最优解法,到底用什么方法能够将时间和空间的效率进一步提升呢?
可以尝试将两个数组先进行排序,然后使用二分查找来确定交叉元素,最后将找到的交叉元素散列到哈希表中,利用哈希函数能够判断哈希表中的元素是否重复。
(3)
vector<int> intersection3(vector<int>& nums1, vector<int>& nums2)
{
vector<int>nums3;
nums3.resize(3 + 2*min(nums1.size(), nums2.size()));
nums3.assign(nums3.size(), 9999);
int key;
//先排序
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
//二分查找交叉元素并将其散列到哈希表中
for (int i=0; i<nums1.size(); ++i)
{
if(binary_search(nums2.begin(), nums2.end(), nums1[i]))
{
int offset = 1;
key = nums1[i] % nums3.size();
while(nums3[key] != 9999 && nums1[i] != nums3[key])
{
key += offset;
offset += 2;
if(key >= nums3.size())
key -= nums3.size();
}
nums3[key] = nums1[i];
}
}
//将交叉元素复制到另外一个数组中并返回
vector<int>ret;
for (int i=0; i<nums3.size(); ++i)
{
if(nums3[i] != 9999)
ret.push_back(nums3[i]);
}
return ret;
}
该方法的时间复杂度O(nlogn),空间复杂度为O(n)。
3.总结
三种方法花了自己两天时间才实现,真心不容易,而且每个算法整体上都比较复杂,只能说还没能力想出那种既简洁又高效的解法,能实现这些不太好看的算法已属不易,继续努力吧。
PS:
- 题目的中文翻译是本人所作,如有偏差敬请指正。
- 其中的“个人分析”和“个人解法”均是本人最初的想法和做法,不一定是对的,只是作为一个对照和记录。