1. 程式人生 > 實用技巧 >[LeetCode] 954. Array of Doubled Pairs 兩倍數對兒陣列

[LeetCode] 954. Array of Doubled Pairs 兩倍數對兒陣列


Given an array of integers A with even length, return true if and only if it is possible to reorder it such that A[2 * i + 1] = 2 * A[2 * i] for every 0 <= i < len(A) / 2.

Example 1:

Input: [3,1,3,6]
Output: false

Example 2:

Input: [2,1,2,6]
Output: false

Example 3:

Input: [4,-2,2,-4]
Output: true
Explanation: We can take two groups, [-2,-4] and [2,4] to form [-2,-4,2,4] or [2,4,-2,-4].

Example 4:

Input: [1,2,4,16,8,4]
Output: false

Note:

  1. 0 <= A.length <= 30000
  2. A.length is even
  3. -100000 <= A[i] <= 100000

這道題說是給了一個偶數長度的陣列,問能不能重新排序,使得從開頭起,每兩個組成一個對,其中後面的數字是前面的數字的兩倍。題目中的座標啥的不用管,本質就是將所有的數字兩兩分組,一個數是另一個數字的兩倍就行了。博主最開始的方法是用一個 HashSet,對於每個數字,查詢是其2倍的數字和是其二分之一的數字(必須整除),若在 HashSet 中存在,則將其移除,否則將遍歷數字加入 HashSet,最後看 HashSet 是否為空。這種方法不適用於有重複數字的情況,所以需要換成 HashMap 來做,然後建立每個數字與其出現次數之間的對映。為了簡便搜尋的過程,可以給數字排序,這樣就可以從最小的數字開始處理,只要查詢其2倍的數字即可。但是當陣列中存在負數的時候,直接排序還是會出問題,比如 -8 會排在 -4 前面,但其實是需要先處理 -4 的,因為 -4 x 2 = -8。所以需要自定義排序的規則,按照數字的絕對值大小排序,這樣 -4 就可以排在 -8 前面。排好序了之後就可以從開頭處理數字了,對於每個數字 key,假如其出現次數大於 key 的2倍的數字出現個數,則說明一定多餘的 key 無法匹配,直接返回 false。否則 key 的2倍數字的對映值減去 key 的對映值,並接續遍歷即可,參見程式碼如下:


解法一:

class Solution {
public:
    bool canReorderDoubled(vector<int>& A) {
        unordered_map<int, int> m;
        for (int num : A) ++m[num];
        vector<int> keys;
        for (auto &a : m) keys.push_back(a.first);
        sort(keys.begin(), keys.end(), [](int i, int j) {return abs(i) < abs(j);});
        for (int key : keys) {
            if (m[key] > m[2 * key]) return false;
            m[2 * key] -= m[key];
        }
        return true;
    }
};

我們也可以使用 TreeMap 來建立對映,利用其自動排序的特性。但是這裡還是存在上面提到的負數的問題,則需要特殊的處理一下。從最小的數字開始處理,由於可能先處理 -8,而不是 -4,所以在找目標數字的時候需要判斷這個數字的正負,若是負數,則除以2,若是正數,則乘以2。然後在判斷假如當前數字是負數,且還是奇數,則直接返回 false,因為沒有比該數還小的數字,所以不能乘以2,又因為其是奇數,不能除以2,所以注孤生。還有就是判斷若當前數字的對映值大於目標數字的對映值,也直接返回 false,這個在上面的解法中解釋過了。之後目標的對映值減去當前數字的對映值,當遍歷結束之後返回 true,參見程式碼如下:


解法二:

class Solution {
public:
    bool canReorderDoubled(vector<int>& A) {
        map<int, int> m;
        for (int num : A) ++m[num];
        for (auto &a : m) {
            if (a.second == 0) continue;
            int want = a.first < 0 ? a.first / 2 : a.first * 2;
            if ((a.first < 0 && a.first % 2 != 0) || a.second > m[want]) return false;
            m[want] -= a.second;
        }
        return true;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/CHANGE_ME


參考資料:

https://leetcode.com/problems/array-of-doubled-pairs/

https://leetcode.com/problems/array-of-doubled-pairs/discuss/209564/Java-Heap-Concise

https://leetcode.com/problems/array-of-doubled-pairs/discuss/203183/JavaC%2B%2BPython-Match-from-the-Smallest-or-Biggest-100


LeetCode All in One 題目講解彙總(持續更新中...)