[C++] LeetCode 493. 翻转对

题目

给定一个数组 nums ,如果 i < jnums[i] > 2*nums[j]我们就将 (i, j)称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
示例 1:
这里写图片描述
示例 2:
这里写图片描述
注意:
1. 给定数组的长度不会超过50000。
2. 输入数组中的所有数字都在32位整数的表示范围内。

题解

这道题目用树状数组加上hash来做。关于树状数组的介绍可以看树状数组百度百科 或者 树状数组
这里树状数组用来计数,表示当前索引对应的值出现的次数。由于数组元素是32位整型,如果直接开一个数组包含nums中所有元素的话(考虑到边界值),数组会很大,且效率很低,考虑题目中给出nums大小不超过50000,所以可以建立一个hash映射,将原始数组排序后映射为有序的索引值,由于题目中考虑的是nums[i] > 2*nums[j],所以原始数组中元素的2倍的值也需要同时映射。
映射好了之后遍历原始数组,对每个元素的2倍值,统计当前大于该值出现的总次数,即考虑树状数组中2*nums[i]对应的索引值右侧元素出现的次数和。

代码

class Solution {
public:
    int lowbit(int x){
        return (int)x&(-1*x);
    }
    int getSum(int x,vector<int> &c){
        int sum=0;
        for(int i=x;i>0;i-=lowbit(i)){
            sum+=c[i];
        }
        return sum;
    }

    void update(vector<int> &c,int x,int v){
        for(int i=x;i<c.size();i+=lowbit(i)){
            c[i]+=v;
        }
    }

    int reversePairs(vector<int>& nums) {
        int maxN=(INT_MAX)/2,minN=(INT_MIN)/2;
        set<int> ss;
        for(auto t:nums){
            ss.insert(t);
            if(t<=maxN&&t>=minN)
                ss.insert(t*2);
        }
        unordered_map<int,int> m;
        int n=ss.size();
        auto it=ss.begin();
        for(int i=1;i<=n;i++){
            m[*it]=i;
            it++;
        }
        vector<int> sum(n+1,0);
        int res=0;
        for(auto t:nums){
            if(t<minN) res+=getSum(n,sum);
            else if(t<maxN){
                int idx=m[2*t];
                res+=(getSum(n,sum)-getSum(idx,sum));
            }
            update(sum,m[t],1);
        }
        return res;
    }
};

提交结果

这里写图片描述

猜你喜欢

转载自blog.csdn.net/lv1224/article/details/80178145
今日推荐