【LeetCode - Java】350. 两个数组的交集 II (简单)

1. 题目描述

在这里插入图片描述

2. 解题思路

交集,意味着要对两个数组具有 “全局观”,“全局观”在程序中的一种体现方法就是统计,因此我可以利用哈希表,分别统计两个数组中每个元素的出现次数,然后取小值构建新的数组。

由于在之前的做题中发现哈希表其实对时间性能的影响较大,在某些情况下使用数组进行代替可以大大提高运行速度,在本题目数组中的元素范围是0到1000,因此我可以构建一个1001长度的数组,用于统计对应下标元素的出现次数。

虽然使用数组代替哈希表的方法确实是可以提高效率的,但数据看起来还是不够优。有方法可以让我只统计一个数组的元素出现个数吗?其实是可以的,我们可以统计长度最短的数组,然后遍历另一数组,在动态更新元素出现个数统计的哈希表的同时构建返回数组

既然数组代替哈希表这个想法是行得通的,那么我们再把上面的思想使用数组进行实现,就可以得到时间更优的解法。

3. 代码实现

3.1 哈希表 统计

public int[] intersect(int[] nums1, int[] nums2) {
        ArrayList<Integer> list = new ArrayList<>();
        Hashtable<Integer, Integer> count1 = count(nums1);
        Hashtable<Integer, Integer> count2 = count(nums2);
        Set<Integer> keySet = count1.keySet();
        for (Integer integer : keySet) {
            if(count2.containsKey(integer)){
                int value = count1.get(integer)<count2.get(integer)?count1.get(integer):count2.get(integer);
                for (int i = 0; i < value; i++) {
                    list.add(integer);
                }
            }
        }
        return list.stream().mapToInt(Integer::valueOf).toArray();
    }
    
    public Hashtable<Integer, Integer> count(int[] nums){
        Hashtable<Integer, Integer> hashtable = new Hashtable<>();
        for (int num : nums) {
            if(hashtable.putIfAbsent(num,1)!=null) {
                hashtable.put(num, hashtable.putIfAbsent(num, 1) + 1);
            }
        }
        return hashtable;
    }

3.2 数组 统计

public int[] intersect(int[] nums1, int[] nums2) {
        ArrayList<Integer> list = new ArrayList<>();
        int[] count1 = count(nums1);
        int[] count2 = count(nums2);
        for (int i = 0; i < count1.length; i++) {
            for (int j = 0; j < Math.min(count1[i], count2[i]); j++) {
                list.add(i);
            }
        }
        return list.stream().mapToInt(Integer::valueOf).toArray();
    }

    public int[] count(int[] nums) {
        int[] c = new int[1001];
        for (int num : nums)
            c[num] = c[num] + 1;
        return c;
    }

3.3 哈希表 统计 改进

public int[] intersect(int[] nums1, int[] nums2) {
        if (nums2.length < nums1.length)
            return intersect(nums2, nums1);
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i : nums1) {
            map.put(i, map.getOrDefault(i, 0) + 1);
        }
        int[] ans = new int[nums1.length];
        int index = 0;
        for (int i : nums2) {
            if (map.containsKey(i)) {
                ans[index++] = i;
                if (map.get(i) == 1)
                    map.remove(i);
                else
                    map.put(i, map.get(i) - 1);
            }
        }
        return Arrays.copyOfRange(ans, 0, index);
    }

3.4 数组 统计 改进

public int[] intersect(int[] nums1, int[] nums2) {
        if (nums2.length < nums1.length)
            return intersect(nums2, nums1);
        int[] count = new int[1001];
        for (int i : nums1) {
            count[i]++;
        }
        int[] ans = new int[nums1.length];
        int index = 0;
        for (int i : nums2) {
            if (count[i] > 0) {
                ans[index++] = i;
                count[i]--;
            }
        }
        return Arrays.copyOfRange(ans, 0, index);
    }

虽然空间性能表现一般,但这是时间性能表现最优的解法。
在这里插入图片描述

3.5 对比

在第一和第二种方法中看似使用了嵌套循环,但实际上该嵌套循环的目的是用于构建返回数组,其时间复杂度是线性的,因此四种方法的时间复杂度都是O(n)。对于空间复杂度而言,哈希表的方法是O(n),而数组的方法是O(1),但其实对于实际空间而言,哈希表占用的空间会更小,因为n必定的小于等于常数1001的。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值