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.

1.分析

全局倒置:满足A[i] > A[j], 0 <= i < j < length;局部倒置:满足A[i] > A[i+1], 0 <= i < length。可以明显看出局部倒置是全局倒置的一种特殊情况,题目判断全局倒置和局部倒置的个数是否相等,即相当于判断数列当中是否存在全局倒置(不是局部倒置),比较容易的求解方法利用二层循环进行求解,但这种方法的时间复杂度过高,参考Grandyang博主的思路,其实如果我们仔细观察的话,就会发现,若某个位置上的值和对应的位置坐标差值超过1,则说明肯定会存在不属于局部倒置的全局倒置。例如:

A[5] = 7, 则数组[0,4]位置上最多容纳[0,7]这8个数中的5个,剩下的其他5和6,必定位于位置5的后面,即存在不属于局部倒置的全局倒置;

A[5] = 3, 则[0, 2]最多占据3个位置,说明位置5的前面必定存在比3大的数,即存在不属于局部倒置的全局倒置。

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

        return true;
    }
};

参考

[1]https://www.cnblogs.com/grandyang/p/8983098.html

为了计算给定数组 `A[0...n-1]` 中的倒置数量,我们可以使用归并排序的思想,同时在合并过程中计数倒置。这是一个经典的减少问题空间复杂度的方法,将原问题分解成规模更小的问题,再合并结果。 以下是伪代码实现: ```pseudo function countInversions(A[], n): // 如果数组长度小于等于1,不存在倒置 if n <= 1: return 0 // 分割数组,找到中间位置 mid mid = floor(n / 2) // 对左半部分右半部分递归调用 countInversions leftInversions = countInversions(A[0...mid], mid) rightInversions = countInversions(A[mid...n], n - mid) // 归并过程,统计倒置 inversionsInMerge = mergeAndCountInversions(A[0...n], leftInversions, rightInversions, mid) return leftInversions + rightInversions + inversionsInMerge function mergeAndCountInversions(leftArray[], rightArray[], leftSize, rightSize): mergedArray[] = new Array(leftSize + rightSize) inversionCount = 0 leftIndex = 0 rightIndex = 0 for i in range(0, leftSize + rightSize): // 当左边数组还有元素且左边元素大于右边时,有倒置 if (leftIndex < leftSize and (rightIndex == rightSize or leftArray[leftIndex] <= rightArray[rightIndex])): mergedArray[i] = leftArray[leftIndex] leftIndex += 1 else: mergedArray[i] = rightArray[rightIndex] rightIndex += 1 inversionCount += leftSize - leftIndex // 统计倒置的数量 // 将剩余的左边元素复制到数组中,并更新倒置计数 while leftIndex < leftSize: mergedArray[i] = leftArray[leftIndex] leftIndex += 1 inversionCount += leftSize - leftIndex // 左边所有剩余元素都是倒置 return inversionCount ``` 这个算法的时间复杂度为 O(n log n),因为每次分割都导致问题规模减半,而在合并阶段,我们需要线性时间来计算统计倒置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值