1. 程式人生 > >[LeetCode] Global and Local Inversions 全域性與區域性的倒置

[LeetCode] Global and Local Inversions 全域性與區域性的倒置

We have some permutation A of [0, 1, ..., N - 1], where N is the length of A.

The number of (global) inversions is the number of i < j with 0 <= i < j < N and A[i] > A[j].

The number of local inversions is the number of i with 0 <= i < N and A[i] > A[i+1].

Return true if and only if the number of global inversions is equal to the number of local inversions.

Example 1:

Input: A = [1,0,2]
Output: true
Explanation: There is 1 global inversion, and 1 local inversion.

Example 2:

Input: A = [1,2,0]
Output: false
Explanation: There are 2 global inversions, and 1 local inversion.

Note:

  • A will be a permutation of [0, 1, ..., A.length - 1].
  • A will have length in range [1, 5000]
    .
  • The time limit for this problem has been reduced.

這道題給了一個長度為n的陣列,裡面是0到n-1數字的任意排序。又定義了兩種倒置方法,全域性倒置和區域性倒置。其中全域性倒置說的是座標小的值大,區域性倒置說的是相鄰的兩個數,座標小的值大。那麼我們可以發現,其實區域性倒置是全域性倒置的一種特殊情況,即區域性倒置一定是全域性倒置,而全域性倒置不一定是區域性倒置,這是解這道題的關鍵點。題目讓我們判斷該陣列的全域性倒置和區域性倒置的個數是否相同,那麼我們想,什麼情況下會不相同?如果所有的倒置都是區域性倒置,那麼由於區域性倒置一定是全域性倒置,則二者個數一定相等。如果出現某個全域性倒置不是區域性倒置的情況,那麼二者的個數一定不會相等。所以問題的焦點就變成了是否能找出不是區域性倒置的全域性倒置。所以為了和區域性倒置區別開來,我們不能比較相鄰的兩個,而是至少要隔一個來比較。我們可以從後往前遍歷陣列,遍歷到第三個數字停止,然後維護一個 [i, n-1] 範圍內的最小值,每次和 A[i - 2] 比較,如果小於 A[i - 2],說明這是個全域性的倒置,並且不是區域性倒置,那麼我們直接返回false即可,參見程式碼如下:

解法一:

class Solution {
public:
    bool isIdealPermutation(vector<int>& A) {
        int n = A.size(), mn = INT_MAX;
        for (int i = n - 1; i >= 2; --i) {
            mn = min(mn, A[i]);
            if (A[i - 2] > mn) return false;
        }
        return true;
    }
};

同理,我們可以反其道行之,我們可以從前往後遍歷陣列,遍歷到倒數第三個數字停止,然後維護一個 [0, i] 範圍內的最大值,每次和 A[i + 2] 比較,如果大於 A[i + 2],說明這是個全域性的倒置,並且不是區域性倒置,那麼我們直接返回false即可,參見程式碼如下:

解法二:

class Solution {
public:
    bool isIdealPermutation(vector<int>& A) {
        int n = A.size(), mx = INT_MIN;
        for (int i = 0; i < n - 2; ++i) {
            mx = max(mx, A[i]);
            if (A[i + 2] < mx) return false;
        }
        return true;
    }
};

其實這道題最叼最炫酷的解法是下面這種解法,最早由grandyang大神的帖子中提出,嗯??grandyang大神??沒錯,就是博主本人啦,哈哈,秀不秀?!?這個解法也是博主腦子靈光一現而想出的,由於原陣列正常的順序應該是 [0, 1, 2, 3, 4...] 這種,即數字和其下標是相同的,所以如果我們發現亂序陣列中某個數字和其座標差的絕對值大於1的話,那麼一定是有非區域性倒置的全域性倒置的存在。猛然這麼一說,可能你會問為啥啊?因為0到n-1中每個數字都是在陣列中存在的,如果當前數字 A[i] 比起座標 i 大1的話,比如 A[i] = 3, i = 1 的時候,那麼陣列的第二個數字是3了,前三個數字suppose是 0,1,2 的,但是由於第二個數字是3了,那麼一定會有一個小於3的數字被擠出前三個數字,這個小於3的數字最多出現在下標為3的位置上,那麼由於數字3出現在了下標為1的位置上,所以non-local的全域性倒置就出現了。同理,如果當前數字 A[i] 比其座標 i 小1的話,比如 A[i] = 1, i = 3 的時候,那麼就是後 n-i 個數字中有一個大於 A[i] 的數字被擠到了前面去了,而且其跟 A[i] 的距離最小為2,所以non-local的全域性倒置就出現了,大聲告訴博主,這個解法精彩不精彩?

解法三:

class Solution {
public:
    bool isIdealPermutation(vector<int>& A) {
        for (int i = 0; i < A.size(); ++i) {
            if (abs(A[i] - i) > 1) return false;
        }
        return true;
    }
};

參考資料: