局部倒置和全局倒置

给你一个长度为 n 的整数数组 nums ,表示由范围 [0, n - 1] 内所有整数组成的一个排列。

全局倒置 的数目等于满足下述条件不同下标对 (i, j) 的数目:

0 <= i < j < n
nums[i] > nums[j]
局部倒置 的数目等于满足下述条件的下标 i 的数目:

0 <= i < n - 1
nums[i] > nums[i + 1]
当数组 nums 中 全局倒置 的数量等于 局部倒置 的数量时,返回 true ;否则,返回 false 。

示例 1:

输入:nums = [1,0,2]
输出:true
解释:有 1 个全局倒置,和 1 个局部倒置。
示例 2:

输入:nums = [1,2,0]
输出:false
解释:有 2 个全局倒置,和 1 个局部倒置。
 
提示:

n == nums.length
1 <= n <= 105
0 <= nums[i] < n
nums 中的所有整数 互不相同
nums 是范围 [0, n - 1] 内所有数字组成的一个排列

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/global-and-local-inversions
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路1

求解局部倒置和全局倒置的数目,并判断两者是否相同。
求解局部倒置:遍历数组即可。
求解全局倒置:暴力解法遍历所有的字符对时间复杂度是\(O(n^2)\)的。结合之前求解逆序对的数目可以想到在归并排序的过程中加入求解逆序对的数目,时间复杂度为O(nlogn)

code

class Solution {
public:
    // 3 5 6
    // 1 2 4
    int tmp[100010];
    long long int global = 0;
    void merge(int start,int mid ,int end,vector<int> & nums)
    {
        int i = start,j = mid + 1;
        int k = start;
        //cout<<start<<" "<<mid<<" "<<end<<endl;
        while(i <= mid && j <= end)
        {
            if(nums[i] <= nums[j])
            {
                tmp[k] = nums[i];
                i ++;
                k ++;
            }
            else
            {
                tmp[k] = nums[j];
                j ++;
                k ++;
                global += (mid - i + 1);
            }
        }

        while(i <= mid)
        {
            tmp[k] = nums[i];
            k ++;
            i++;
        }

        while(j <= end)
        {
            tmp[k] = nums[j];
            k ++;
            j ++;
        }

        for(int i = start;i <= end;i ++)
        {
            nums[i] = tmp[i];
            //cout<<tmp[i]<<" ";
        }

        //cout<<endl;

    }
    
    void merge_sort(vector<int> & nums,int start,int end)
    {
        if(start >= end) return;
        int mid = (start + end) / 2;
        merge_sort(nums,start,mid);
        merge_sort(nums,mid + 1,end);
        merge(start,mid,end,nums);
    }
    bool isIdealPermutation(vector<int>& nums) {
        
        int n = nums.size();


        int local = 0;
        for(int i = 0;i < n - 1;i ++)
        {
            if(nums[i] > nums[i + 1]) local ++;
        }

        merge_sort(nums,0,nums.size() - 1);

        return local == global;
        
    }
};

解题思路2

全局倒置是包含局部倒置的,要使得两者相等,就需要数组中不存在非局部倒置,也就是nums[i] > nums[j],其中i < j - 1。朴素的判断方法需要使用两重循环,时间复杂度为\(O(n ^ 2)\)
也就是对于每一个nums[i],需要判断是否存在{nums[i+2],nums[i+3],....,nums[n-1]}小于nums[i]。也就是判断nums[i]和min{nums[i+2],nums[i+3],.....,nums[n-1]}之间的大小关系,如果nums[i] < min,则继续,否则返回false.这样就可以倒序遍历并维护后缀的最小值即可。

code

class Solution {
public:
    bool isIdealPermutation(vector<int>& nums) {
        
        int n = nums.size();
        int minSuffix = nums[n - 1];

        for(int i = n - 3;i >= 0; i --)
        {
            if(nums[i] > minSuffix) return false;
            else
            {
                minSuffix = min(minSuffix,nums[i + 1]);
            }
        }

        return true;
    }
};
posted on 2022-11-16 11:28  huangxk23  阅读(40)  评论(0)    收藏  举报