leetcode493(翻转对:归并排序)

给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
示例 1:
输入: [1,3,2,3,1]
输出: 2
示例 2:
输入: [2,4,3,5,1]
输出: 3

题解(一):归并排序,在归并排序的过程中,假设对于某归并数组而言,我们已经分别求出了其左右子数组的翻转对数目,并已将左右子数组分别排好序,则该数组中的翻转对数目,就等于两个子数组的翻转对数目之和,加上翻转对左右端点分别位于左右两个子数组的翻转对数目。

class Solution {
    public int reversePairs(int[] nums) {
        if(nums.length==0)
            return 0;
        return mergeSort(nums,0, nums.length-1);
    }
    //归并排序算法
    public int mergeSort(int[]nums,int left,int right){
        if(left==right)
            return 0;
        int mid=(left+right)/2;
        //递归
        int ans=mergeSort(nums,left,mid)+mergeSort(nums,mid+1,right);
        int left_bound=left;
        int right_bound=mid+1;
        //找出翻转对的数量(左右端点分别位于左右两个有序数组中)
        while(left_bound<=mid){
            while(right_bound<=right&&(long)(nums[left_bound])>2*(long)nums[right_bound]){
                right_bound++;
            }
            ans+=(right_bound-mid-1);
            left_bound++;
        }
        int[]sorted=new int[right-left+1];
        int leftPtr=left;
        int rightPtr=mid+1;
        int i=0;
        //左右两个有序数组合并
        while(leftPtr<=mid||rightPtr<=right){
            if(leftPtr>mid){
                sorted[i++]=nums[rightPtr++];
            }else if(rightPtr>right){
                sorted[i++]=nums[leftPtr++];
            }else{
                if(nums[leftPtr]<nums[rightPtr]){
                    sorted[i++]=nums[leftPtr++];
                }else{
                    sorted[i++]=nums[rightPtr++];
                }
            }
        }
        for (int j = 0; j < sorted.length; j++) {
            nums[left + j] = sorted[j];
        }
        return ans;
    }
}

题解(二):构造树状数组

class Solution {
    public int reversePairs(int[] nums) {
        Set<Long> allNumbers = new TreeSet<Long>();
        for (int x : nums) {
            allNumbers.add((long) x);
            allNumbers.add((long) x * 2);
        }
        // 利用哈希映射将离散整数投影到连续空间
        Map<Long, Integer> values = new HashMap<Long, Integer>();
        int idx = 0;
        for (long x : allNumbers) {
            values.put(x, idx);
            idx++;
        }

        int ret = 0;
        Tree bit = new Tree(values.size());
        for (int i = 0; i < nums.length; i++) {
            int left = values.get((long) nums[i] * 2), right = values.size() - 1;
            ret += bit.query(right + 1) - bit.query(left + 1);
            bit.update(values.get((long) nums[i]) + 1, 1);
        }
        return ret;
    }
}

//树状数组类
class Tree {
    int[] tree;
    int n;

    public Tree(int n) {
        this.n = n;
        this.tree = new int[n + 1];
    }

    public static int lowbit(int x) {
        return x & (-x);
    }

    public void update(int x, int d) {
        while (x <= n) {
            tree[x] += d;
            x += lowbit(x);
        }
    }

    public int query(int x) {
        int ans = 0;
        while (x != 0) {
            ans += tree[x];
            x -= lowbit(x);
        }
        return ans;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值