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; } };
參考資料:
https://leetcode.com/problems/global-and-local-inversions/solution/
https://leetcode.com/problems/global-and-local-inversions/discuss/113656/My-3-lines-C++-Solution