349. 两个数组的交集 题解

题目描述:349. 两个数组的交集 - 力扣(LeetCode)

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

 方法一:

解题思路:

我们可以采用排序和双指针的方法来求两个数组的交集。

  1. 对两个输入数组 nums1nums2 进行排序,以便能够有效地在有序数组中查找交集元素。

  2. 初始化两个指针 ptr1ptr2,分别指向数组 nums1nums2 的起始位置。

  3. 创建一个结果数组,用于存储交集元素。同时,创建一个变量 count 用于记录结果数组中的元素个数。

  4. 开始循环遍历两个有序数组:

    • 比较 nums1[ptr1]nums2[ptr2]
    • 如果两个元素相等,则将这个元素添加到结果数组中,然后增加 ptr1ptr2
    • 如果 nums1[ptr1] 小于 nums2[ptr2],则增加 ptr1
    • 如果 nums1[ptr1] 大于 nums2[ptr2],则增加 ptr2
  5. 循环继续,直到任一指针达到其数组的末尾。

  6. 返回结果数组,同时更新 count 为结果数组中的元素个数。

代码:

// 比较函数,用于排序
int compare(const void *a, const void *b) {
    return (*(int *)a - *(int *)b);
}

int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
    qsort(nums1, nums1Size, sizeof(int), compare);
    qsort(nums2, nums2Size, sizeof(int), compare);
    
    int *result = (int *)malloc(sizeof(int) * (nums1Size < nums2Size ? nums1Size : nums2Size));
    int count = 0;
    
    int i = 0, j = 0;
    while (i < nums1Size && j < nums2Size) {
        if (nums1[i] == nums2[j]) {
            // 避免重复添加相同元素
            if (count == 0 || nums1[i] != result[count - 1]) {
                result[count++] = nums1[i];
            }
            i++;
            j++;
        } else if (nums1[i] < nums2[j]) {
            i++;
        } else {
            j++;
        }
    }
    
    *returnSize = count;
    return result;
}

方法二:

解题思路:

利用哈希集合

  1. 初始化一个哈希集合,用于存储 nums1 数组中的元素。

  2. 遍历 nums1 数组,将其中的元素加入哈希集合中。

  3. 创建一个结果数组,用于存储交集元素。

  4. 遍历 nums2 数组,对于其中的每个元素,判断是否在哈希集合中出现:

    • 如果出现,则将该元素加入结果数组,并从哈希集合中移除,以避免重复添加相同元素。
  5. 返回结果数组。

代码:

typedef struct
{
    int *data;
    int size;
} HashSet;

// 初始化哈希集合
HashSet* initHashSet()
{
    HashSet* set = (HashSet*)malloc(sizeof(HashSet));
    set->data = (int *)calloc(1000, sizeof(int));  // 注意初始化一定要是0
    set->size = 0;
    return set;
}

// 将元素加入哈希集合
void addToHashSet(HashSet* set, int num)
{
    set->data[num] = 1;
    set->size++;
}

// 判断元素是否在哈希集合中
int isInHashSet(HashSet* set, int num)
{
    return set->data[num];
}

// 释放哈希开辟的内存
void freeHashSet(HashSet* set)
{
    free(set->data);
    free(set);
}


int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize)
{
    HashSet* set = initHashSet();
    // 将数组1中的元素添加到哈希集合中
    for(int i=0;i<nums1Size;i++)
    {
        addToHashSet(set, nums1[i]);
    }
    int* ret = (int*)malloc(sizeof(int)*(nums1Size<nums2Size?nums2Size:nums1Size));
    int count = 0;
    // 查询
    for(int i=0;i<nums2Size;i++)
    {
        if(isInHashSet(set, nums2[i]))
        {
            // 添加
            ret[count++] = nums2[i];
            set->data[nums2[i]] = 0; // 避免重复添加
        }
    }
    *returnSize = count;
    freeHashSet(set);
    return ret;
}

总结:

哈希集合方法:

  • 时间复杂度:O(m + n),其中 m 是 nums1 的长度,n 是 nums2 的长度。

    • 创建哈希集合需要 O(m) 的时间,因为需要将 nums1 中的元素加入集合。
    • 遍历 nums2 并检查元素是否在哈希集合中需要 O(n) 的时间。
    • 最终的结果遍历需要 O(min(m, n)) 的时间,其中 min(m, n) 是结果数组的长度。
  • 空间复杂度:O(m) 或 O(n),取决于 nums1 数组的大小。

    • 哈希集合需要存储 nums1 中的元素,因此需要 O(m) 的额外空间。

排序和双指针方法:

  • 时间复杂度:O(m * log m + n * log n + m + n),其中 m 是 nums1 的长度,n 是 nums2 的长度。

    • 排序 nums1nums2 需要 O(m * log m) 和 O(n * log n) 的时间。
    • 遍历两个有序数组需要 O(m + n) 的时间。
    • 最终的结果遍历需要 O(min(m, n)) 的时间。
  • 空间复杂度:O(1)。

    • 这种方法只使用了常量级的额外空间用于存储指针和计数。

总结起来,如果在意时间复杂度,当 mn 较小时,两种方法的时间复杂度都差不多,但哈希集合方法在一些特定情况下可能会稍微快一些。然而,如果在意空间复杂度,排序和双指针方法的空间复杂度更低。


本次内容到此结束了!如果你觉得这篇博客对你有帮助的话 ,希望你能够给我点个赞,鼓励一下我。感谢感谢……

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值