• 315. 计算右侧小于当前元素的个数


       分析:暴力法是可以做的但是时间复杂度O(n2),竞赛选手很容易想到用线段树,树状数组来优化时间复杂度,这里贴几种容易理解的方法

    方法一:归并排序,归并排序可以求逆序对,这是我们熟悉的,所以在归并排序的合并过程,我们可以求出右边小于当前数的有几个,这道题需要返回每个位置的右边小于它的元素数量,我们可以用一个位置数组来

      维护位置信息,统计个数的时候直接加入到当前的位置。(思想:归并排序交换数字,改为交换位置)

    class Solution {
        int[] count;
        public List<Integer> countSmaller(int[] nums) {
            int n = nums.length;
            count = new int[n];
            List<Integer> res = new ArrayList<>();
            int[] pos = new int[n];
            for(int i = 0; i < n; i++) {
                pos[i] = i;
            }
            sort(nums,0,n-1,pos);
            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,right,mid,pos);
            }
        }
                                                                // 位置数组,交换的时候就交换位置数组
        public void merge(int[] nums, int left, int right, int mid, 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]]) { // 这样,保证r左边到mid都是小于它的数
                    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);
        }
    }

     方法二:排序二叉树

    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 + 1; // 向右插入加上小于等于当前节点的个数
                root.right = insert(res,root.right,node,i);
            }
            return root;
        }
    }
    class Node {
        int val, count;  // count保存当前小于等于当前节点的个数
        Node left, right;
        public Node (int val) {
            this.val = val;
        }
    }

    方法三:树状数组

    class Solution {
        int[] tr;
        int n;
        int lowbit(int x)
        {
            return x & -x;
        }
        void add(int x, int v)
        {
            for (int i = x; i <= n; i += lowbit(i))
                tr[i] += v;
        }
        int sum(int x)
        {
            int res = 0;
            for (int i = x; i != 0; i -= lowbit(i))
                res += tr[i];
            return res;
        }
        public List<Integer> countSmaller(int[] nums) {
            //HashMap + 排序 离散化
            n = nums.length;
            tr = new int[n + 1];
            int[] arr = nums.clone();
            Arrays.sort(arr);
    
            //Hash的过程
            Map<Integer, Integer> hash = new HashMap<>();
            int id = 0;
            for (int x : arr) 
                if (!hash.containsKey(x))
                    hash.put(x, ++ id);
                    
            List<Integer> res = new LinkedList<>();
            for (int i = n - 1; i >= 0; i --)
            {
                int x = hash.get(nums[i]);
                add(x, 1);
                res.add(0, sum(x - 1));//<
            }
            return res;
        }
    }
  • 相关阅读:
    公式中表达单个双引号【"】和空值【""】的方法及说明
    Ext.net CRUD
    水煮肉片
    配置传入电子邮件(Office SharePoint Server 管理中心帮助)
    CodeSmith开发系列资料总结
    报表中的Excel操作之Aspose.Cells(Excel模板)
    40个UI设计工具和资源
    配置Sharepoint传入/传出电子邮件a
    联想乐Pad_A1获取root权限
    Windows Azure
  • 原文地址:https://www.cnblogs.com/yonezu/p/13283285.html
Copyright © 2020-2023  润新知