zoukankan      html  css  js  c++  java
  • 两个数组的交集 II [ LeetCode

     
    原题地址:https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/description/
     
    给定两个数组,写一个方法来计算它们的交集。

    例如:

    给定 nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2, 2].

    注意:

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

    跟进:

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

    以上是原题

     
    我们先按照常规思路解题,再逐步分析最后的集中特殊情况。
     
      思路:
      1、增加一个计数器,用来记录其中一个数组元素出现的次数。
      2、遍历另一个数组,如果该数组元素在计数器中有记录且记录的次数大于1,将该数字新增到结果数组中,同时计数器该数字记录的次数减1。
      实现代码如下:
     1     public int[] intersect(int[] nums1, int[] nums2) {
     2         Map<Integer, Integer> counter = new HashMap<>(); //计数器,key为数组中的数字,value为该数字在数组中出现的次数
     3         for (int i = 0; i < nums1.length; i++) {
     4             int num = nums1[i];
     5             if (counter.containsKey(num)) {
     6                 counter.put(num, counter.get(num) + 1);
     7             } else {
     8                 counter.put(num, 1);
     9             }
    10         }
    11         List<Integer> tempList = new ArrayList<>();
    12         for (int i = 0; i < nums2.length; i++) {
    13             int num = nums2[i];
    14             if (counter.containsKey(num) && counter.get(num) > 0) {
    15                 counter.put(num, counter.get(num) - 1); //计数器中记录该数字的次数减1
    16                 tempList.add(num); //将该数字添加到list中
    17             }
    18         }
    19         int[] result = new int[tempList.size()];
    20         //为满足题目返回值类型,将list转换为int数组
    21         for (int i = 0; i < result.length; i++) {
    22             result[i] = tempList.get(i);
    23         }
    24         return result;
    25     }

      OK,基本功能已经实现,下一步我们一起思考如何满足几个跟进问题:

    • 如果给定的数组已经排好序呢?你将如何优化你的算法?

      思路:因为两个数组都是有序的,那我们完全可以用两个指针c1和c2分别顺序扫描两个数组,得到两个数字m和n,有以下三种关系:

      1、m == n,则该数字是重复数字,将该数字添加到结果数组中,同时将两个指针分别后移一位。

      2、m > n,我们需要将c2指针后移一位。

      3、m < n,我们需要将c1指针后移一位。

      重复以上步骤,直到c1或c2其中一个指针已移动到数组末端。

      代码实现如下:

     1     public int[] intersect(int[] nums1, int[] nums2) {
     2         int cur1 = 0, cur2 = 0; // 定义指针,指向数组开始位置
     3         List<Integer> list = new ArrayList<>();
     4         while (cur1 < nums1.length && cur2 < nums2.length) { // 循环结束条件:任何一个指针指向对应数组的末端
     5             int num1 = nums1[cur1];
     6             int num2 = nums2[cur2];
     7             if (num1 == num2) { // 重复数字,加入结果列表中
     8                 list.add(num1);
     9                 cur1++;
    10                 cur2++;
    11             } else if (num1 < num2) { // 将cur1指针后移一位,继续下一次比较
    12                 cur1++;
    13             } else { // 将cur2指针后移一位,继续下一次比较
    14                 cur2++;
    15             }
    16         }
    17         int[] result = new int[list.size()];
    18         // 为满足题目返回值类型,将list转换为int数组
    19         for (int i = 0; i < list.size(); i++) {
    20             result[i] = list.get(i);
    21         }
    22         return result;
    23     }
    • 如果 nums1 的大小比 nums2 小很多,哪种方法更优?
      我们来对比上述两种方法:
      假设nums1和nums2的长度为l1, l2。
     
      第一种:
        不考虑结尾转换int数组的循环,一共有两处循环:
        1、第一次循环nums1初始化计数器。
        2、第二次循环nums2与计数器中存储的数值作比较。
        无论如何,这两种循环都需要完全执行,实际循环次数为 l1 + l2。
     
      第二种:
        不考虑结尾转换int数组的循环,一共有一处循环:
        1、每次循环同时在nums1和nums2中取值对比,如果相等,同时移动两个指针,一个指针结束后,循环结束。因为 l1 比 l2 小很多,只需要执行完l1次循环即可,实际消耗时间远远小于第一种方法。
     
        最差的情况:最差的情况是nums1和nums2中完全没有一个重复数字,且nums1中的最后一个元素大于nums2的倒数第二个元素,nums2的最后一个元素大于nums1的倒数第二个元素,在这种情况下,第二种方法的循环也同样需要执行 l1 + l2次。
     
      因此,只有在极端情况下,两种方法效率大约相等,其他任何情况下,第二种方法是要优于第一种方法的。
     
    • 如果nums2的元素存储在磁盘上,内存是有限的,你不能一次加载所有的元素到内存中,你该怎么办?

      如果nums2的元素多到无法一次性加载到内存中,那我们应该:

      1、将nums1中的数字初始化计数器。

      2、使用缓冲流读取文件的一部分数据,计数器中有记录且记录的次数大于1,将该数字新增到结果数组中,计数器中该数字记录的次数减1,这样完成了这一部分数据的统计。

      3、接着再读取文件中下一部分数据,重复步骤2。

      

    OK,以上是这个问题的一些想法,如果朋友们有更好的方式,欢迎留言交流哈~

      

  • 相关阅读:
    68
    56
    Django manager 命令笔记
    Django 执行 manage 命令方式
    Django 连接 Mysql (8.0.16) 失败
    Python django 安装 mysqlclient 失败
    H.264 SODB RBSP EBSP的区别
    FFmpeg—— Bitstream Filters 作用
    MySQL 远程连接问题 (Windows Server)
    MySQL 笔记
  • 原文地址:https://www.cnblogs.com/zfLee/p/9332552.html
Copyright © 2011-2022 走看看