350. 两个数组的交集 II

2019/07/18 23:04 下午 posted in  leetcode 数组 双指针

问题

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

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

示例 2:

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

说明:

  • 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
  • 我们可以不考虑输出结果的顺序。

进阶:

  • 如果给定的数组已经排好序呢?你将如何优化你的算法?
  • 如果 nums1 的大小比 nums2 小很多,哪种方法更优?
  • 如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

解法

问题比较简单。可以遍历两个数组,获得数字出现的频次,然后对比两个频次即可。或者可以直接排序两个数组,然后使用两个指针分别遍历数组即可。

解法

频次法

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        if(nums1.length > nums2.length) {
            return intersect(nums2, nums1);
        }
        //这里使用hashmap,因为数字是不定长的。
        Map<Integer, Integer> map1 = new HashMap<>(nums1.length);
        for (Integer i: nums1) {
            Integer count = map1.get(i);
            if (count == null) {
                map1.put(i, 1);
            } else {
                map1.put(i, count+1);
            }
        }
        Map<Integer, Integer> map2 = new HashMap<>(nums2.length);
        for (Integer i: nums2) {
            Integer count = map2.get(i);
            if (count == null) {
                map2.put(i, 1);
            } else {
                map2.put(i, count+1);
            }
        }
        Iterator iter = map1.entrySet().iterator(); 
        List<Integer> result = new LinkedList();
        //遍历两个频次map即可,这里使用小的那个map遍历。可以减少查询次数
        while(iter.hasNext()) {
            Map.Entry<Integer, Integer> entry = (Map.Entry) iter.next(); 
            Integer key = entry.getKey(); 
            Integer val1 = entry.getValue(); 
            Integer val2 = map2.get(key);
            if(val2 != null) {
                int count = Math.min(val1, val2);
                while (count-- > 0) {
                    result.add(key);
                }
            }
        }
        
        //最终生成结果,因为没有用从List到int[]的方便转换方法。
        int[] res = new int[result.size()];
        for(int m=0;m<res.length;m++)
        {
            res[m]=result.get(m);
        }
        return res;
    }
}

排序遍历法

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        if(nums1.length > nums2.length) {
            return intersect(nums2, nums1);
        }
        List<Integer> result = new LinkedList();
        
        //排序两个数组
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        //遍历两个数组
        for (int i = 0,j=0; i<nums1.length && j<nums2.length;) {
            //相等则加入result
            if (nums1[i] == nums2[j]) {
                result.add(nums1[i]);
                i++;
                j++;
            } else if (nums1[i] < nums2[j]){
                // 这里注意只有其中一个往前推进。
                i++;
            } else {
                j++;
            }
        }
        
        int[] res = new int[result.size()];
        for(int m=0;m<res.length;m++)
        {
            res[m]=result.get(m);
        }
        return res;
    }
}