zoukankan      html  css  js  c++  java
  • LeetCode Notes_#350_两个数组的交集 II

    LeetCode Notes_#350_两个数组的交集 II

    Contents

    题目

    给定两个数组,编写一个函数来计算它们的交集。
    示例 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的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

    解答

    方法1:哈希表统计出现次数

    比较笨的办法是统计两个数组的数字出现次数,然后遍历哈希表,对于交集的元素,将两个数组出现次数的较小值作为交集的出现次数。

    class Solution {
        public int[] intersect(int[] nums1, int[] nums2) {
            List<Integer> res = new ArrayList<>();
            HashMap<Integer, Integer> map1 = new HashMap<>();
            HashMap<Integer, Integer> map2 = new HashMap<>();
            for(int num : nums1){
                map1.put(num, map1.getOrDefault(num, 0) + 1);
            }
            for(int num : nums2){
                map2.put(num, map2.getOrDefault(num, 0) + 1);
            }
            for(int key: map1.keySet()){
                if(map2.containsKey(key)){
                    int times = Math.min(map1.get(key), map2.get(key));
                    for(int i = 1;i <= times;i++){
                        res.add(key);
                    }
                }
            }
            int[] resArray = new int[res.size()];
            for(int i = 0;i <= res.size() - 1;i++){
                resArray[i] = res.get(i);
            }
            return resArray;
        }
    }

    BTW,这里最后为了返回int[]类型,不可以使用toArray()方法,因为这样只能得到Integer[]类型的数组,最后反正还是得重新通过遍历赋值得到int[]

    复杂度分析

    时间复杂度:O(m + n),m和n分别是两个数组的长度
    空间复杂度:O(m + n)

    优化

    其实不必要对于统计两个数组的元素出现频率,这样的空间复杂度有点高。可以只统计其中较小数组的频率。然后遍历另外一个数组,如果遇到哈希表存储的元素,就直接将其加入到交集数组中,然后将哈希表中这个元素的频次减去1。
    这个方法对应于进阶里的第二问。但是我这里为了方便并没有写寻找较小数组的逻辑,默认统计nums1的频率。

    class Solution {
        public int[] intersect(int[] nums1, int[] nums2) {
            HashMap<Integer, Integer> map = new HashMap<>();
            for(int num: nums1){
                map.put(num, map.getOrDefault(num, 0) + 1);
            }
            List<Integer> res = new ArrayList<>();
            for(int num: nums2){
                if(map.containsKey(num) && map.get(num) != 0){
                    res.add(num);
                    map.put(num, map.get(num) - 1);
                }
            }
            int[] resArray = new int[res.size()];
            for(int i = 0; i <= resArray.length - 1;i++){
                resArray[i] = res.get(i);
            }
            return resArray;
        }
    }

    复杂度分析

    时间复杂度:O(m + n),m和n分别是两个数组的长度
    空间复杂度:O(m)O(n),如果使用较小数组来统计,则为O(min(m,n)

    方法2:排序后使用双指针

    这个对应于进阶当中的第一问,相当于使用双指针的方式,节省了空间复杂度。

    class Solution {
        public int[] intersect(int[] nums1, int[] nums2) {
            Arrays.sort(nums1);
            Arrays.sort(nums2);
            List<Integer> res = new ArrayList<>();
            int i = 0,j = 0;
            while(i <= nums1.length - 1 && j <= nums2.length - 1){
                if(nums1[i] < nums2[j]){
                    i++;
                }
                else if(nums1[i] == nums2[j]){
                    res.add(nums1[i]);
                    i++;
                    j++;
                }else{
                    j++;
                }
            }
            int[] resArray = new int[res.size()];
            for(int k = 0;k <= res.size() - 1;k++){
                resArray[k] = res.get(k);
            }
            return resArray;
        }
    }

    复杂度分析

    时间复杂度:O(mlogm + nlogn),排序两个数组的复杂度
    空间复杂度:O(min(m, n)),需要借助一个临时的ArrayList变量

    进阶问题3

    对应进阶问题三,如果内存十分小,不足以将数组全部载入内存,那么必然也不能使用哈希这类费空间的算法,只能选用空间复杂度最小的算法,即排序+双指针法。
    但还需要改造,一般说排序算法都是针对于内部排序,一旦涉及到跟磁盘打交道(外部排序),则需要特殊的考虑。归并排序是天然适合外部排序的算法,可以将分割后的子数组写到单个文件中,归并时将小文件合并为更大的文件。当两个数组均排序完成生成两个大文件后,即可使用双指针遍历两个文件(用指针遍历文件,而不需要将整个文件加载进入内存),如此可以使空间复杂度最低。

  • 相关阅读:
    python 5 条件判断
    python 4学习 list 和 tuple
    python 3 学习字符串和编码
    python 1 学习廖雪峰博客
    c++11 thread的学习
    C++ 11 Lambda表达式!!!!!!!!!!!
    c++11 右值的学习
    TreeMap
    二分查找
    solr in action 第三章
  • 原文地址:https://www.cnblogs.com/Howfars/p/13822774.html
Copyright © 2011-2022 走看看