Count of Smaller Numbers After Self

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

Example 1

Input: [5, 2, 6, 1]
Output: [2, 1, 1, 0]
Explanation:
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.

Example 2

Input: [1, 2, 3, 4]
Output: [0, 0, 0, 0]

思路: O(NlogN)算法沿用Count of Smaller numberscount of smaller numbers before self。还是用线段树求解,但是这个题目有负数的情况,解决方法很简单,就是求得max和min之后,把整个数组解空间往右shift min位子就可以了。注意如果min > 0, 那么没必要shift; 那么segment tree的class一点都不需要改变,只需要把count的代码,每次+ Math.abs(min);把before的代码稍微改改就可以用了,注意题目要求是逆着count,所以list add的时候是add(0,count);

class Solution {
    public List<Integer> countSmaller(int[] nums) {
        List<Integer> list = new ArrayList<Integer>();
        if(nums == null || nums.length == 0) {
            return list;
        }
        int minvalue = nums[0], maxvalue = nums[0];
        for(int i : nums) {
            minvalue = Math.min(minvalue, i);
            maxvalue = Math.max(maxvalue, i);
        }
        // 因为有负数,所以需要shift 坐标 math.abs(minvalue), 但是如果minvalue > 0,则没必要shift;
        minvalue = Math.min(minvalue, 0);
        int size = maxvalue - minvalue + 1;
        SegmentTree tree = new SegmentTree(size);
        for(int i = nums.length - 1; i >= 0; i--) {
            if(nums[i] == minvalue) {
                list.add(0, 0);
            } else {
                list.add(0, tree.querySum(0, nums[i] + Math.abs(minvalue) - 1));
            }
            tree.add(nums[i] + Math.abs(minvalue), 1);
        }
        return list;
    }
    
    private class SegmentTreeNode {
        public int start, end;
        public int sum;
        public SegmentTreeNode left, right;
        public SegmentTreeNode(int start, int end) {
            this.start = start;
            this.end = end;
        }
    }
    
    private class SegmentTree {
        public SegmentTreeNode root;
        public int size;
        public SegmentTree(int size) {
            this.size = size;
            this.root = buildTree(0, size - 1);
        }
        
        private SegmentTreeNode buildTree(int start, int end) {
            if(start > end) {
                return null;
            }
            SegmentTreeNode root = new SegmentTreeNode(start, end);
            if(start == end) {
                return root;
            }
            int mid = start + (end - start) / 2;
            root.left = buildTree(start, mid);
            root.right = buildTree(mid + 1, end);
            return root;
        }
        
        private int querySum(SegmentTreeNode root, int start, int end) {
            if(root.start == start && root.end == end) {
                return root.sum;
            }
            int mid = root.start + (root.end - root.start) / 2;
            int leftsum = 0, rightsum = 0;
            if(start <= mid) {
                leftsum = querySum(root.left, start, Math.min(mid, end));
            }
            if(end >= mid + 1) {
                rightsum = querySum(root.right, Math.max(start, mid + 1), end);
            }
            return leftsum + rightsum;
        }
        
        private void add(SegmentTreeNode root, int index, int value) {
            if(root.start == root.end && root.end == index) {
                root.sum += value;
                return;
            }
            int mid = root.start + (root.end - root.start) / 2;
            if(index <= mid) {
                add(root.left, index, value);
            } else {
                add(root.right, index, value);
            }
            root.sum = root.left.sum + root.right.sum;
        }
        
        public int querySum(int start, int end) {
            return querySum(root, start, end);
        }
        
        public void add(int index, int value) {
            add(root, index, value);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值