zoukankan      html  css  js  c++  java
  • 315. 计算右侧小于当前元素的个数

     方法一:利用归并排序保存位置数组,交换时交换位置数组

    class Solution {
        int[] count;
        public List<Integer> countSmaller(int[] nums) {
            int n = nums.length;
            count = new int[n];
            int[] pos = new int[n];
            for(int i = 0; i < n; i++) pos[i] = i;
            sort(nums,0,n-1,pos);
            List<Integer> res = new ArrayList<>();
            for(int num : count) res.add(num);
            return res;
        }
    
        public void sort(int[] nums, int left, int right, int[] pos) {
            if(left < right) {
                int mid = (left + right) >> 1;
                sort(nums,left,mid,pos);
                sort(nums,mid+1,right,pos);
                merge(nums,left,mid,right,pos);
            }
        }
    
        public void merge(int[] nums, int left, int mid, int right, int[] pos) {
            int[] temp = new int[right-left+1];
            int t = 0, l = left, r = mid + 1;
            while(l <= mid && r <= right) {
                if(nums[pos[l]] <= nums[pos[r]]) {
                    count[pos[l]] += r - (mid + 1);
                    temp[t++] = pos[l++];
                } else {
                    temp[t++] = pos[r++];
                }
            }
            while(l <= mid) {
                count[pos[l]] += r - (mid + 1);
                temp[t++] = pos[l++];
            }
            while(r <= right) {
                temp[t++] = pos[r++];
            }
            System.arraycopy(temp,0,pos,left,temp.length);
        }
    
    }

    方法二:建树,节点保存一个count值,计算当前节点的左子树有多少个数(小于当前节点的值),将数组倒序插入树中,节点向当前节点右边插入时,计算小于它的个数

    class Solution {
        public List<Integer> countSmaller(int[] nums) {
            int n = nums.length;
            Integer[] res = new Integer[n];
            Arrays.fill(res,0);
            Node root = null;
            for(int i = n - 1; i >= 0; i--) {
                root = insert(res,root,new Node(nums[i]),i);
            }
            return Arrays.asList(res);
        }
        public Node insert(Integer[] res, Node root, Node node, int i) {
            if(root == null) {
                root = node;
                return root;
            }
    
            if(root.val >= node.val) {
                root.count++;
                root.left = insert(res,root.left,node,i);
            } else {
                res[i] += root.count;
                root.right = insert(res,root.right,node,i);
            }
            return root;
        }
    }
    class Node {
        int val, count;
        Node left, right;
        public Node (int val) {
            this.val = val;
            count = 1;
        }
    }

    方法三:树状数组(不知道数据范围先离散化处理)

    class Solution {
        int[] bitArr;
        int n;
        public List<Integer> countSmaller(int[] nums) {
            n = nums.length;
            bitArr = new int[n+1];
            int[] arr = nums.clone();
            Map<Integer,Integer> map = new HashMap<>();
            Arrays.sort(arr);
            int idx = 0;
            for(int num : arr) {
                if(!map.containsKey(num)) {
                    map.put(num,++idx);
                }
            }
            List<Integer> res = new LinkedList<>();
            for(int i = n - 1; i >= 0; i--) {
                int x = map.get(nums[i]);
                res.add(0,count(x-1));
                add(x,1);
            }
            return res;
        }
    
        int lowBit(int x) {return x & (-x);}
        void add(int x, int y) {
            for(int i = x; i <= n; i += lowBit(i)) bitArr[i] += y;
        }
        int count(int x) {
            int res = 0;
            for(int i = x; i != 0; i -= lowBit(i)) res += bitArr[i];
            return res;
        }
    }

    方法四:线段树

    class Solution {
        public List<Integer> countSmaller(int[] nums) {
            LinkedList<Integer> res = new LinkedList<>();
            int len = nums.length;
            if(len == 0) return res;
            //获取区间范围
            int start = nums[0], end = nums[0];
            for(int i = 0; i < len; i++){
                if(nums[i] < start) start = nums[i];
                if(nums[i] > end) end = nums[i];
            }
            //构建树
            SegmentTreeNode root = build(start, end);
            //从右向左,边插入边计数
            for(int i = len - 1; i >= 0; i--){
                //计数小于该元素的区间,所以要减一
                res.addFirst(count(root, start, nums[i] - 1));
                insert(root, nums[i], 1);
            }
            return res;
        }
        //线段树节点,包含左右最值和该区间叶子节点数,子区间不断递减
        private class SegmentTreeNode{
            int start, end, count;
            SegmentTreeNode left, right;
    
            public SegmentTreeNode(int start, int end){
                this.start = start;
                this.end = end;
                this.count = 0;
                left = null;
                right = null;
            }
        }
        //构建线段树,不断递减区间长度
        private SegmentTreeNode build(int start, int end){
            if(start > end) return null;
            SegmentTreeNode root = new SegmentTreeNode(start, end);
            if(start != end){
                int mid = start + (end - start) / 2;
                root.left = build(start, mid);
                root.right = build(mid + 1, end);
            }
            return root;
        }
        //插入并更新叶子节点
        private void insert(SegmentTreeNode root, int index, int val){
    
            if (root.start == index && root.end == index){
                root.count += val;
                return;
            }
    
            int mid = root.start + (root.end - root.start) / 2;
            if (index >= root.start && index <= mid)
                insert(root.left, index, val);
            if (index > mid && index <= root.end)
                insert(root.right, index, val);
            //更新父节点的统计数,便于正好落在区间上的查找
            root.count = root.left.count + root.right.count;
        }
        //根据区间统计
        private int count(SegmentTreeNode root, int start, int end){
            //nums[i] - 1, 排除相等的情况
            if(start > end) return 0;
            //递归到叶子节点,获取计数值
            if (start == root.start && end == root.end){
                return root.count;
            }
            int mid = root.start + (root.end - root.start) / 2;
            int leftcount = 0, rightcount = 0;
            //统计左半区
            if (start <= mid){
                if (mid < end)
                    leftcount = count(root.left, start, mid);
                else
                    leftcount = count(root.left, start, end);
            }
            //统计右半区
            if (mid < end){
                if (start <= mid)
                    rightcount = count(root.right, mid + 1, end);
                else
                    rightcount = count(root.right, start, end);
            }
            return (leftcount + rightcount);
        }
    }
  • 相关阅读:
    Codeforces Round #562题解
    Codeforces Round #561题解
    CF1107E Vasya and Binary String(区间dp)
    NC110113 Summer Earnings(bitset)
    NC112798 XOR-pyramid(dp)
    NC23051 华华和月月种树(离线+树状数组)
    py.path模块
    stat模块
    pwd模块
    PrettyTable模块
  • 原文地址:https://www.cnblogs.com/yonezu/p/13368878.html
Copyright © 2011-2022 走看看