Loading

两个数组中的交集

1.问题描述

  • 给定两个数组,编写一个函数来计算它们的交集。

    示例 1:

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

    示例 2:

    输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
    输出:[9,4]

    说明:

    • 输出结果中的每个元素一定是唯一的。
    • 我们可以不考虑输出结果的顺序。

2.求解

哈希表法

  • 将一个数组存储到哈希表中,遍历另一个数组找出交集
  • 注意题目中要求输出的不能有重复元素,于是使用set集合存储交集,最后转化成int数组返回

代码如下

/*
* 执行用时:3 ms, 在所有 Java 提交中击败了95.82% 的用户
* 内存消耗:38.9 MB, 在所有 Java 提交中击败了71.86% 的用户
* */
public int[] intersection(int[] nums1, int[] nums2) {
    Set<Integer> set = new HashSet<>();
    if(nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0){
        return null;
    }
    Map<Integer,Integer> map = new HashMap<>();
    for(int x : nums1){
        map.put(x,x);
    }
    for(int x : nums2){
        if(map.containsKey(x)){
            set.add(x);
        }
    }
    int[] ans = new int[set.size()];
    int i = 0;
    for(int x : set){
        ans[i] = x;
        i++;
    }
    return ans;
}
  • 时间复杂度、空间复杂度均为O(m+n)

ps:java8中引入了流的操作,因此我们可以简化最后的返回结果,直接将set使用stream转化成int数组

return set.stream().mapToInt(i -> i).toArray();

​ 其中stream()方法是将结构转化为流

​ mapToInt()方法是将特定函数应用此流然后返回IntStream,最后我们再对IntStream进行toArray操作当然就得到一个int数组了

  • 流的高级操作

    public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> set = Arrays.stream(nums1).boxed().collect(Collectors.toSet());
        return Arrays.stream(nums2).distinct().filter(set::contains).toArray();
    }
    
    • 第一行将nums1转换成了流,然后进行装箱操作(转换为对象),最后再用collect收集为Set
    • 第二行将nums2转换成了流,然后进行去重,增加了一个过滤方法要求必须是set的contains方法返回true的元素,最后再转换成数组

排序+双指针

  • 先对两个数组进行排序,然后在用两个指针进行比较,找寻相同元素
/*
 * 执行用时:5 ms, 在所有 Java 提交中击败了28.20% 的用户
 * 内存消耗:38.6 MB, 在所有 Java 提交中击败了87.56% 的用户
 * */
public int[] intersection(int[] nums1, int[] nums2) {
    Arrays.sort(nums1);
    Arrays.sort(nums2);
    List<Integer> list = new ArrayList<>();
    int i = 0, j = 0;
    int index = 0;
    while (i < nums1.length && j < nums2.length) {
        if (nums1[i] == nums2[j]) {
            if (index == 0 || nums1[i] != list.get(index - 1)) {
                list.add(nums1[i]);
                index++;
            }
            i++;
            j++;
        } else if (nums1[i] < nums2[j]) {
            i++;
        } else {
            j++;
        }
    }
    return list.stream().mapToInt(Integer::valueOf).toArray();
}
  • 这里傻了,用了list,转换造成性能开销,直接用一个大小为两个数组之和的数组最后切割下可能更好

又用int数组试了一下

/*
 * 执行用时:1 ms, 在所有 Java 提交中击败了99.97% 的用户
 * 内存消耗:38.9 MB, 在所有 Java 提交中击败了68.68% 的用户
 * */
public int[] intersection(int[] nums1, int[] nums2) {
    Arrays.sort(nums1);
    Arrays.sort(nums2);
    int i = 0, j = 0;
    int index = 0;
    int[] ans = new int[nums1.length + nums2.length];
    while (i < nums1.length && j < nums2.length) {
        if (nums1[i] == nums2[j]) {
            if (index == 0 || nums1[i] != ans[index - 1]) {
                ans[index] = nums1[i];
                index++;
            }
            i++;
            j++;
        } else if (nums1[i] < nums2[j]) {
            i++;
        } else {
            j++;
        }
    }
    return Arrays.copyOfRange(ans, 0, index);
}

果然速度快了相当多,这里注意下无法对int型数组进行切割,但是可以使用Arrays.copyofRange()方法复制一个新数组

排序+二分搜索

/*
 * 执行用时:2 ms, 在所有 Java 提交中击败了99.48% 的用户
 * 内存消耗:38.6 MB, 在所有 Java 提交中击败了90.99% 的用户
 * */
public int[] intersection(int[] nums1, int[] nums2) {
    Arrays.sort(nums1);
    Arrays.sort(nums2);
    int[] ans = new int[nums1.length + nums2.length];
    int index = 0;
    for (int x : nums2) {
        if (binarySearch(nums1, x)) {
            if (index == 0 || x != ans[index - 1]) {
                ans[index] = x;
                index++;
            }
        }
    }
    return Arrays.copyOfRange(ans, 0, index);
}

boolean binarySearch(int[] nums, int target) {
    int left = 0;
    int right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            return true;
        }
        if (nums[mid] > target) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return false;
}
  • 二分搜索可以只对一个数组排序,然后遍历另一个数组,进行搜索,但是需要使用set去重,于是这里我直接对两个数组都进行了排序
posted @ 2020-11-02 21:42  水纸杯  阅读(524)  评论(0)    收藏  举报