字节微软阿里腾讯快手面试题——349. 两个数组的交集

349. 两个数组的交集

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

示例 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] 也是可通过的

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

哈希集

class Solution {
    // 主函数,用于找到两个数组的交集
    public int[] intersection(int[] nums1, int[] nums2) {
        // 使用两个 Set 来存储 nums1 和 nums2 中的元素
        Set<Integer> set1 = new HashSet<Integer>();
        Set<Integer> set2 = new HashSet<Integer>();
        
        // 将 nums1 中的所有元素加入到 set1 中
        for (int num : nums1) {
            set1.add(num);
        }
        // 将 nums2 中的所有元素加入到 set2 中
        for (int num : nums2) {
            set2.add(num);
        }
        
        // 调用 getIntersection 函数,找到两个 Set 的交集
        return getIntersection(set1, set2);
    }

    // 辅助函数,用于找到两个 Set 的交集
    public int[] getIntersection(Set<Integer> set1, Set<Integer> set2) {
        // 如果 set1 的大小大于 set2,交换 set1 和 set2 的位置,确保第一个参数总是较小的 Set。重点。
        if (set1.size() > set2.size()) {
            return getIntersection(set2, set1);
        }
        
        // 使用 Stream API 计算交集,并将结果收集到 int 数组中。直接用下面被注释的代码也可以。
        //return set1.stream()
        //           .filter(set2::contains)  // 过滤出在 set2 中也存在的元素
        //           .mapToInt(Integer::intValue)  // 将 Integer 转换为 int
        //           .toArray();  // 收集为 int 数组
        
        // 创建一个新的 Set 用于存储交集元素
        Set<Integer> intersectionSet = new HashSet<Integer>();
        // 遍历较小的 Set(set1),如果元素也存在于较大的 Set(set2)中,则将该元素加入到 intersectionSet 中
        for (int num : set1) {
            if (set2.contains(num)) {
                intersectionSet.add(num);
            }
        }
        
        // 将交集 Set 转换为数组
        int[] intersection = new int[intersectionSet.size()];
        int index = 0;
        for (int num : intersectionSet) {
            intersection[index++] = num;
        }
        
        // 返回交集数组
        return intersection;
    }
}
  • 时间复杂度: O ( m + n ) O(m+n) O(m+n) ,其中 m m m n n n 分别是两个数组的长度。使用两个集合分别存储两个数组中的元素需要 O ( m + n ) O(m+n) O(m+n) 的时间,遍历较小的集合并判断元素是否在另一个集合中需要 O ( min ⁡ ( m , n ) ) O(\min (m, n)) O(min(m,n)) 的时间,因此总时间复杂度是 O ( m + n ) O(m+n) O(m+n)
  • 空间复杂度: O ( m + n ) O(m+n) O(m+n) ,其中 m m m n n n 分别是两个数组的长度。空间复杂度主要取决于两个集合。

双指针+排序

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        // 对 nums1 和 nums2 进行排序
        Arrays.sort(nums1);
        Arrays.sort(nums2);

        int length1 = nums1.length; // 获取 nums1 的长度
        int length2 = nums2.length; // 获取 nums2 的长度
        
        int[] intersection = new int[length1 + length2]; // 创建一个足够大的数组,用于存储交集元素。
        int index = 0; // 交集数组的当前索引
        int index1 = 0; // nums1 的当前索引
        int index2 = 0; // nums2 的当前索引

        // 使用双指针方法遍历 nums1 和 nums2
        while (index1 < length1 && index2 < length2) {
            int num1 = nums1[index1]; // nums1 中当前元素
            int num2 = nums2[index2]; // nums2 中当前元素

            if (num1 == num2) { // 如果两个元素相等,表示找到一个交集元素
                // 保证加入元素的唯一性,重点。
                if (index == 0 || num1 != intersection[index - 1]) {
                    intersection[index++] = num1; // 将交集元素加入到结果数组中
                }
                index1++; // 移动 nums1 的指针
                index2++; // 移动 nums2 的指针
            } else if (num1 < num2) { // 如果 nums1 中的元素小于 nums2 中的元素
                index1++; // 移动 nums1 的指针
            } else { // 如果 nums2 中的元素小于 nums1 中的元素
                index2++; // 移动 nums2 的指针
            }
        }

        // 返回交集数组中有效的部分,重点。
        return Arrays.copyOfRange(intersection, 0, index);
    }
}
  • 时间复杂度: O ( m log ⁡ m + n log ⁡ n ) O(m \log m+n \log n) O(mlogm+nlogn) ,其中 m m m n n n 分别是两个数组的长度。对两个数组排序的时间复杂度分别是 O ( m log ⁡ m ) O(m \log m) O(mlogm) O ( n log ⁡ n ) O(n \log n) O(nlogn) ,双指针寻找交集元素的时间复杂度是 O ( m + n ) O(m+n) O(m+n) ,因此总时间复杂度是 O ( m log ⁡ m + n log ⁡ n ) O(m \log m+n \log n) O(mlogm+nlogn)
  • 空间复杂度: O ( log ⁡ m + log ⁡ n ) O(\log m+\log n) O(logm+logn) ,其中 m m m n n n 分别是两个数组的长度。空间复杂度主要取决于排序使用的额外空间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值