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

    Q:给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

    示例:
    输入: [5,2,6,1]
    输出: [2,1,1,0]
    解释:
    5 的右侧有 2 个更小的元素 (2 和 1).
    2 的右侧仅有 1 个更小的元素 (1).
    6 的右侧有 1 个更小的元素 (1).
    1 的右侧有 0 个更小的元素.

    A:
    1.分治法
    考虑使用归并排序。
    以题目所给的[5,2,6,1]为例,先把数组变成pairs,pairs里面存的是数值和初始所在的index,存初始index是为了往count里面存放数量时可以找到初始的这个值所对应的index。
    使用分治,第一次归并的数组是[[5,0]|[2,1]].
    初始化:

    5比2大,先把[2,1]对应放到temp的位置上。

    因为左侧没有读完,说明左侧没有读完的数比右侧的所有数都要大,所以5对应的count位置上要加上右侧所有的数字的总个数

    第二次归并的数组是[[6,2]|[1,3]],类似上面,归并结果是[[1,3],[6,2]]
    当前count为[1,0,1,0]

    第三次归并的数组是[[2,1],[5,0]|[1,3],[6,2]]
    初始化:

    2比1大,1放入temp,j++

    2比6小,说明2比6之前到mid的所有值都大(因为如果不比6左侧值都大不可能能让j移到6上去),所以把mid至6之间值的总个数加到2对应的count上,即j-mid-1 = 1
    再把2放入temp,i++

    5比6小,说明5比6之前到mid的所有值都大,所以把mid至6之间值的总个数加到5对应的count上,即j-mid-1 = 1
    再把5放入temp,i++

    此时左侧所有数值都放入temp中,右侧还有6没放入。右侧当前已是最大,不可能右侧还有比其更小的值了,直接加入temp中

    至此,已完成count的计算。

    代码:

        private int[] count;
    
        public List<Integer> countSmaller(int[] nums) {
            List<Integer> result = new ArrayList<>();
            if (nums.length == 0)
                return result;
            int n = nums.length;
            Pair<Integer, Integer>[] pairs = new Pair[n];
            count = new int[n];
            for (int i = 0; i < n; i++) {
                pairs[i] = new Pair<>(nums[i], i);
            }
            merge_sort(pairs, 0, n - 1);
            for (int i = 0; i < n; i++)
                result.add(count[i]);
            return result;
        }
    
        private void merge_sort(Pair<Integer, Integer>[] pairs, int left, int right) {
            if (left >= right)
                return;
            int mid = (left + right) / 2;
            merge_sort(pairs, left, mid);
            merge_sort(pairs, mid + 1, right);
            merge(pairs, left, mid, right);
        }
    
        private void merge(Pair<Integer, Integer>[] pairs, int left, int mid, int right) {
            int i = left, j = mid + 1, k = left;
            Pair<Integer, Integer>[] temp = Arrays.copyOf(pairs, pairs.length);
            while (i <= mid && j <= right) {
                if (pairs[i].getKey() <= pairs[j].getKey()) {
                    int index = pairs[i].getValue();
                    count[index] += (j - mid - 1);//mid到j之间的所有数字都比i小
                    temp[k] = pairs[i];
                    i++;
                    k++;
                } else {
                    temp[k] = pairs[j];
                    j++;
                    k++;
                }
            }
            while (i <= mid) {//当前i比右侧数组的所有值都大
                int index = pairs[i].getValue();
                count[index] += right - mid;
                temp[k] = pairs[i];
                i++;
                k++;
            }
            while (j <= right) {
                temp[k] = pairs[j];
                j++;
                k++;
            }
            for (int m = left; m <= right; m++) {
                pairs[m] = temp[m];
            }
        }
    

    2.使用二叉排序树
    从后往前插入。
    还是以[5,2,6,1]为例。
    初始化:

    6比1大,插入右侧,存入的值在1的count上+1

    2比1大,存入值在1的count上+1;比6小,放入6左侧,6的count+1

    5比1大,存入值在1的count上+1;比6小,放入6的左侧,6的count+1;比2大,存入值在2的count上+1

    若是5前面还有一个7
    7比1大,存入值在1的count上+1;比6大,存入值再存入6的count上+1

    代码:

        class TreeNode {
            int val;
            int count;
            TreeNode left;
            TreeNode right;
    
            TreeNode(int val) {
                this.val = val;
                left = null;
                right = null;
                count = 0;
            }
        }
    
        public List<Integer> countSmaller(int[] nums) {
            List<Integer> result = new ArrayList<>();
            if (nums.length == 0)
                return result;
            int[] res = new int[nums.length];
            TreeNode root = null;
            for (int i = nums.length - 1; i >= 0; i--) {
                root = insert(root, new TreeNode(nums[i]), res, i);
            }
            for (int i : res) {
                result.add(i);
            }
            return result;
        }
    
        private TreeNode insert(TreeNode root, TreeNode node, int[] res, int i) {
            if (root == null) {
                root = node;
                return root;
            }
            if (node.val <= root.val) {
                root.count++;
                root.left = insert(root.left, node, res, i);
            } else {
                res[i] += root.count + 1;
                root.right = insert(root.right, node, res, i);
            }
            return root;
        }
    
  • 相关阅读:
    Linux安全应用之防垃圾邮件服务器的构建
    Postfix邮件系统安装配置视频
    Linux常用的安全工具
    Linux系统安全加固(一)
    全球开源软件发展趋势分析
    安装配置FreeBSD9全过程体验
    P1441-砝码称重
    POJ-2376 Cleaning Shifts
    P1514-引水入城
    P1378-油滴扩展
  • 原文地址:https://www.cnblogs.com/xym4869/p/12612023.html
Copyright © 2011-2022 走看看