53 两数组的交集(Intersection of Two Arrays)

这篇博客详细介绍了如何解决寻找两个数组交集的问题,提供了三种不同的算法:排序+合并、二分搜索和哈希表。每种方法的时间复杂度和空间复杂度都有所不同,其中哈希表的方法在时间和空间效率上表现最优。源码中给出了C++的实现,包括排序后的合并、二分搜索以及哈希表的交集查找。这些方法均考虑了重复元素的处理并确保结果中元素唯一。
摘要由CSDN通过智能技术生成

1 题目

题目:两数组的交集(Intersection of Two Arrays)
描述:给出两个数组,写出一个方法求出它们的交集。

  1. 结果中的每个元素必须是唯一的。

lintcode题号——547,难度——easy

样例1:

输入: nums1 = [1, 2, 2, 1], nums2 = [2, 2], 
输出: [2].

样例2:

输入: nums1 = [1, 2], nums2 = [2], 
输出: [2].

2 解决方案

2.1 思路

  本题可以使用多种方式来解,排序+合并、排序+二分、哈希表。
  使用先排序再合并的方式,在逐一合并的过程中找到交集,从两个数组头部开始,对比大小,将找到的相同值放入结果中,注意去除重复元素,以此类推直到其中一个数组为空即可。
  使用二分搜索的方式,将其中一个数组排序,然后遍历另一个数组中的所有元素在已排序的数组中进行二分搜索,找到的元素放入结果中,同样需要去除重复元素。
  使用哈希表的方式,将其中一个数组放入哈希表中,然后遍历另一个数组中的所有元素在哈希表中进行查找,找到的元素放入结果中,同样也要去除重复。

2.3 时间复杂度

  假设数组一的长度m,数组二的长度n,m要大于n。
  先排序再合并的方式,两个数组都排序耗时O(n*log n)O(m*log m),合并操作的耗时O(m + n),总时间复杂度为O(nlogn + mlogm + m + n) = O(n*log n + m*log m)
  使用二分搜索的方式,对其中一个数组排序耗时O(m*log m),遍历另一个数组的耗时O(n),在已排序数组中进行二分搜索的耗时O(log m),总时间复杂度为O(m*log m + n*log m) = O((m+n)*log m),可以看出该方式中将较小的数组进行排序可以减少计算耗时。
  使用哈希表的方式,将其中一个数组放入哈希表耗时O(m),遍历另一个数组的耗时O(n),在哈希表中查找一个元素的耗时为O(1),总时间复杂度为O(m + n)

2.4 空间复杂度

  三种方式的空间复杂度也不一样。
  先排序再合并的方式,不使用额外空间,空间复杂度为O(1)
  使用二分搜索的方式,不使用额外空间,空间复杂度为O(1)
  使用哈希表的方式,把较小的数组放入哈希表,使用的额外空间较小,空间复杂度为O(min{m,n})

3 源码

3.1 排序+合并的方式

细节:

  1. 排序+合并,时间复杂度O(nlog n + mlog m),空间复杂度O(1)。

C++版本:

/**
* @param nums1: an integer array
* @param nums2: an integer array
* @return: an integer array
*          we will sort your return value in output
*/
vector<int> intersection(vector<int> &nums1, vector<int> &nums2) {
    // write your code here
    vector<int> result;
    if (nums1.empty() || nums2.empty())
    {
        return result;
    }

    // 分别对两个数组排序
    sort(nums1.begin(), nums1.end());
    sort(nums2.begin(), nums2.end());

    // 合并
    int i = 0;
    int j = 0;
    while (i < nums1.size() && j < nums2.size())
    {
        if (nums1.at(i) < nums2.at(j))
        {
            i++;
        }
        else if (nums1.at(i) > nums2.at(j))
        {
            j++;
        }
        else
        {
            if (result.empty() || nums1.at(i) != result.back()) // 跳过重复的元素,先判断结果容器是否空,再取back(),否则越界
            {
                result.push_back(nums1.at(i));
            }
            i++;
            j++;
        }
    }

    return result;
}

3.2 二分搜索的方式

细节:

  1. 二分搜索,时间复杂度O((m+n)*log m),空间复杂度O(1)。
  2. 两个数组都可能包含重复元素,结果中使用set进行去重。

C++版本:

/**
* @param nums1: an integer array
* @param nums2: an integer array
* @return: an integer array
*          we will sort your return value in output
*/
vector<int> intersection(vector<int> &nums1, vector<int> &nums2) {
    // write your code here
    vector<int> result;
    if (nums1.empty() || nums2.empty())
    {
        return result;
    }

    // 比较两个数组长度
    vector<int> * small = nullptr;
    vector<int> * big = nullptr;
    if (nums1.size() < nums2.size())
    {
        small = &nums1;
        big = &nums2;
    }
    else
    {
        small = &nums2;
        big = &nums1;
    }

    // 对较短的数组排序
    sort(small->begin(), small->end());

    // 遍历较长的数组元素,逐个进行二分搜索
    unordered_set<int> resultSet;
    for (auto it : *big)
    {
        // 二分搜索
        if (binarySearch(*small, it))
        {
            resultSet.insert(it); // 去重
        }
    }

    // 构造结果
    for (auto it : resultSet)
    {
        result.push_back(it);
    }

    return result;
}

bool binarySearch(vector<int> & nums, int target)
{
    int start = 0;
    int end = nums.size() - 1;
    while (start + 1 < end)
    {
        int mid = start + (end - start) / 2;
        if (nums.at(mid) < target)
        {
            start = mid;
        }
        else if (nums.at(mid) > target)
        {
            end = mid;
        }
        else
        {
            return true;
        }
    }

    if (nums.at(start) == target)
    {
        return true;
    }
    if (nums.at(end) == target)
    {
        return true;
    }

    return false;
}

3.3 哈希表的方式

细节:

  1. 哈希表,时间复杂度O(m + n),空间复杂度O(min{m,n})。
  2. 两个数组都可能包含重复元素,结果中使用set进行去重。

C++版本:

/**
* @param nums1: an integer array
* @param nums2: an integer array
* @return: an integer array
*          we will sort your return value in output
*/
vector<int> intersection(vector<int> &nums1, vector<int> &nums2) {
    // write your code here
    vector<int> result;
    if (nums1.empty() || nums2.empty())
    {
        return result;
    }

    // 比较两个集合大小
    vector<int> * small;
    vector<int> * big;
    if (nums1.size() < nums2.size())
    {
        small = &nums1;
        big = &nums2;
    }
    else
    {
        small = &nums2;
        big = &nums1;
    }

    // 较小的放入hash表中
    set<int> hash;
    for (auto it : *small)
    {
        hash.insert(it);
    }

    // 遍历较大的集合
    set<int> resultSet; // 产生的结果也需要去重,因为num2中可能有重复,不要求有序的话,可以使用unordered_set
    for (auto it : *big)
    {
        if (hash.find(it) != hash.end())
        {
            resultSet.insert(it);
        }
    }

    // 构造结果
    for (auto it : resultSet)
    {
        result.push_back(it);
    }

    return result;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值