LeetCode 315 Count of Smaller Numbers After Self(树状数组)

129 篇文章 0 订阅
60 篇文章 0 订阅

You are given an integer array nums and you have to return a new counts array.The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:

Given nums = [5, 2, 6, 1]

To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.

Return the array [2, 1, 1, 0].

Subscribe to see which companies asked this question


题目链接:https://leetcode.com/problems/count-of-smaller-numbers-after-self/


题目分析:其实就是求逆序数,可以用树状数组或归并排序实现,这里用的树状数组(感觉比归并好些的多。。。)

这是一开始写的,老老实实中规中矩的排序离散化,跑了26ms

public class Solution {
    
    class Data implements Comparable {
        int val, pos;
        
        public Data(int val, int pos) {
            this.val = val;
            this.pos = pos;
        }
        
        @Override  
        public int compareTo(Object o) {  
            Data data = (Data) o;  
            if (this.val >= data.val) {  
                return 1;  
            }  
            else {
                return -1;
            }
        }
    }
    
    public int lowbit(int x) {
        return x & (-x);
    }
    
    public void add(int x, int len, int[] cnt) {
        for (int i = x; i <= len; i += lowbit(i)) {
            cnt[i] ++;
        } 
    }
    
    public int getCnt(int x, int[] cnt) {
        int ans = 0;
        for (int i = x; i > 0; i -= lowbit(i)) {
            ans += cnt[i];
        }
        return ans;
    }
    
    public List<Integer> countSmaller(int[] nums) {
        List<Integer> ans = new ArrayList<>();
        int len = nums.length;
        if (len == 0) {
            return ans;
        }
        Data[] d = new Data[len];
        int[] cnt = new int[len + 1];
        int[] nums2 = new int[len + 1];
        int[] rev = new int[len];
        for (int i = 0; i < len; i ++) {
            d[i] = new Data(nums[i], i + 1);
        }
        Arrays.sort(d);
        nums2[d[0].pos] = 1;
        int id = 1;
        for(int i = 1; i < len; i ++) {
            if (d[i].val == d[i - 1].val) {
                nums2[d[i].pos] = id;
            }
            else {
                nums2[d[i].pos] = ++ id;
            }
        }
        int revCnt = 0;
        for (int i = len; i >= 1; i --) {
            add(nums2[i], len, cnt);
            rev[revCnt ++] = getCnt(nums2[i] - 1, cnt);
        }
        for (int i = revCnt - 1; i >= 0; i --) {
            ans.add(rev[i]);
        }
        return ans;
    }
}

看了discuss里的一种离散化方法,瞬间8ms,不过那种离散化方法只适用于负数不太小,正数不太大的情况

public class Solution {

    public int lowbit(int x) {
        return x & (-x);
    }
    
    public void add(int x, int len, int[] cnt) {
        for (int i = x; i <= len; i += lowbit(i)) {
            cnt[i] ++;
        } 
    }
    
    public int getCnt(int x, int[] cnt) {
        int ans = 0;
        for (int i = x; i > 0; i -= lowbit(i)) {
            ans += cnt[i];
        }
        return ans;
    }
    
    public List<Integer> countSmaller(int[] nums) {
        List<Integer> ans = new ArrayList<>();
        int len = nums.length;
        if (len == 0) {
            return ans;
        }
        int[] nums2 = new int[len + 1];
        int[] rev = new int[len];
        int mi = Integer.MAX_VALUE;
        int ma = Integer.MIN_VALUE;
        for (int i = 0; i < len; i ++) {
            mi = Math.min(nums[i], mi);
        }
        for (int i = 1; i <= len; i ++) {
            nums2[i] = nums[i - 1] - mi + 1;
            ma = Math.max(ma, nums2[i]);
        }
        int[] cnt = new int[ma + 1];
        int revCnt = 0;
        for (int i = len; i >= 1; i --) {
            add(nums2[i], ma, cnt);
            rev[revCnt ++] = getCnt(nums2[i] - 1, cnt);
        }
        for (int i = revCnt - 1; i >= 0; i --) {
            ans.add(rev[i]);
        }
        return ans;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值