LeetCode 350: 兩個數組的交集 II Intersection of Two Arrays II

題目:

給定兩個數組,編寫一個函數來計算它們的交集。java

Given two arrays, write a function to compute their intersection.python

示例 1:算法

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

示例 2:數組

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

說明:app

  • 輸出結果中每一個元素出現的次數,應與元素在兩個數組中出現的次數一致。
  • 咱們能夠不考慮輸出結果的順序。

Note:函數

  • Each element in the result should appear as many times as it shows in both arrays.
  • The result can be in any order.

進階:優化

  • 若是給定的數組已經排好序呢?你將如何優化你的算法?
  • 若是 nums1 的大小比 nums2 小不少,哪一種方法更優?
  • 若是 nums2 的元素存儲在磁盤上,磁盤內存是有限的,而且你不能一次加載全部的元素到內存中,你該怎麼辦?

Follow up:指針

  • What if the given array is already sorted? How would you optimize your algorithm?
  • What if nums1's size is small compared to nums2's size? Which algorithm is better?
  • What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once?

解題思路:

​ 暴力解題就不說了。code

  • 哈希表:排序

    利用哈希映射求得其中一個數組每一個數字出現的頻次。遍歷另外一個數組,每遇到相同數字,其存儲頻次減一,若頻次爲 0,則移出哈希映射。如:

    輸入 nums1 = [4, 9, 5], nums2 = [9, 4, 9, 8, 4 }
    計算 nums1 頻次: { 4:1, 9:1, 5:1 },Key = {4 , 9, 5 }
    遍歷 nums2:
    9 存在於 Key,9 頻次 -1 爲 0,9 移出 HashMap:{ 4:1, 5:1 }
    4 存在於 Key,4 頻次 -1 爲 0,4 移出 HashMap:{ 5:1 }
    9 不存在於 Key,跳過
    8 不存在於 Key,跳過
    ...
    輸出:{9, 4}
  • 雙指針:

    先把兩個數組排序,定義兩個指針 i, j ,移動指針

    • 若是 nums1 [i] == nums2 [j],則該數共有。
    • 若是不等,則移動元素值小的指針。

    如:

    輸入 nums1 = [ 4, 9, 5 ], nums2 = [ 9, 4, 9, 8, 4 ]
    排序 nums1 = [ 4, 5, 9 ], nums2 = [ 4, 4, 8, 9, 9 ]
    雙指針遍歷:[ 4, 5, 9],[ 4, 4, 8, 9, 9 ]
                                  ^                 ^
     4 = 4, 存入 res = [4], 移動雙指針: [ 4, 5, 9],[ 4, 4, 8, 9, 9 ]
                                                                            ^                 ^
    5 > 4, 移動指向 4 的指針:[ 4, 5, 9],[ 4, 4, 8, 9, 9 ]
                                                           ^                      ^
    5 < 8, 移動指向 5 的指針:[ 4, 5, 9],[ 4, 4, 8, 9, 9 ]
                                                                ^                 ^
    
    9 > 8, 移動指向 8 的指針:[ 4, 5, 9],[ 4, 4, 8, 9, 9 ]
                                                                ^                      ^
    
    9 = 9, 存入 res = [4, 9], 移動雙指針: [ 4, 5, 9 ],[ 4, 4, 8, 9, 9 ]
                                                                                       ^                        ^
    超過 nums1 長度,結束,返回 res

回答進階問題:

  1. 雙指針法主要耗時操做就是排序操做的排序算法。對於有序數組固然使用雙指針解題。
  2. 在一個數組長度遠小於另外一個數組時,哈希表解題更優,只需哈希統計長度較小的數組的元素頻次,遍歷長數組便可。時間複雜度取決於長數組長度。若是用雙指針法,對長數組的排序將消耗更多時間。
  3. 若是內存有限,只能選擇雙指針法或暴力破解,無需額外空間複雜度。使用哈希表時在最壞狀況下:每一個數字只出現一次,HashMap 元素頻次統計後,其大小可能大於內存容量。

哈希表解題:

Java:

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        HashMap<Integer, Integer> map = new HashMap<>();
        List<Integer> list = new ArrayList<>();//動態數組
        for (Integer num : nums1) map.put(num, map.getOrDefault(num, 0) + 1);//統計元素出現頻次
        for (Integer num : nums2) {//遍歷另外一個數組
            if (map.containsKey(num)) {
                int tmp = map.get(num)-1;//頻次減一
                if (tmp == 0) map.remove(num);//頻次爲 0 時,移出 HashMap
                else map.put(num, tmp);//不然更新頻次
                list.add(num);//加入動態數組
            }
        }
        //轉爲數組並返回
        int size=list.size();
        int[] res = new int[size];
        for (int i = 0; i < size; i++) res[i] = list.get(i);
        return res;
    }
}

Python:

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        count = dict(collections.Counter(nums1))# 自帶庫統計元素出現頻次,並轉爲 Dict 類型

        res = []
        for num in nums2:# 遍歷另外一個數組
            if num in count:
                count[num] -= 1# 詞頻減一
                res.append(num)
                if count[num] <= 0:# 詞頻爲 0 時,移出字典
                    count.pop(num)
        return res

雙指針解題:

Java:

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        List<Integer> list = new ArrayList<>();
        Arrays.sort(nums1);//排序數組
        Arrays.sort(nums2);
        int i = 0, j = 0;//定義指針
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] < nums2[j]) i++;//移動較小數的指針
            else if (nums1[i] > nums2[j]) j++;//移動較小數的指針
            else {
                //兩數相等則爲交集,存入動態數組,移動雙指針
                list.add(nums1[i]);
                i++;
                j++;
            }
        }
        //轉爲數組並返回
        int[] res = new int[list.size()];
        for (int k = 0; k < list.size(); k++) res[k] = list.get(k);
        return res;
    }
}

Python:

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        i, j, nums1_size, nums2_size = 0, 0, len(nums1), len(nums2)# 定義指針,計算數組長度
        nums1, nums2, res = sorted(nums1), sorted(nums2), []# 排序數組,初始化返回數組 res
        while i < nums1_size and j < nums2_size:# 循環條件爲指針不溢出
            if nums1[i] < nums2[j]:# 移動數值較小的指針
                i += 1
            elif nums1[i] > nums2[j]:# 移動數值較小的指針
                j += 1
            else:
                res.append(nums1[i])# 數值相等,則爲交集,移動雙指針
                i += 1
                j += 1
        return res

歡迎關注微.信..公.衆.號: 愛寫Bug

愛寫Bug.png

相關文章
相關標籤/搜索