zoukankan      html  css  js  c++  java
  • 315. 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:

    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].

    链接: http://leetcode.com/problems/count-of-smaller-numbers-after-self/

    题解:

    一开始没有什么想法,后来看tag有segment tree,正好前面也做过于是撸了一棵出来,结果碰到一个超常的数据会超时。又试了一下简单的Brute Force,也会超时。最后还是去Discuss区观摩大神们,发现有好些解法,比如以下

    1. 利用Merge Sort count Inversion: https://leetcode.com/discuss/73256/mergesort-solution 
    2. Binary Search Tree: https://leetcode.com/discuss/73280/my-simple-ac-java-binary-search-code 
    3. Building BST :  https://leetcode.com/discuss/73762/9ms-short-java-bst-solution-get-answer-when-building-bst
    4. Segment Tree:  https://leetcode.com/discuss/73233/complicated-segmentree-solution-hope-to-find-a-better-one
    5. Fenwich Tree (<- fastest I've seen) :   https://leetcode.com/discuss/74961/7ms-java-solution-using-binary-indexed-tree
    6. Bit comparision : https://leetcode.com/discuss/74994/nlogn-divide-and-conquer-java-solution-based-bit-comparison

    下面代码是参考yavinci大神的,从右向左遍历数组并且构建BST,当前节点node左侧全部是值小于或者等于当前节点val的节点,当前结点node.count就是他们的和。而每次addNode假如发现逆序,则可以取当前节点的count值返回。 一个小地方是,把结果全部加入到List<Integer>里,最后再reverse这个list,要比每次list.add(0, count)速度要快很多。这个算法worst case  time complexity其实还是O(n2),要有AVL Tree才能缩短到O(nlogn)。 二刷还是要研究一下merge sort的解法。  比较难的Fenwick Tree解法代码很简单,速度也最快,也留给以后再研究了。

    Time Complexity - O(n2), Space Complexity - O(n)

    public class Solution {
        private class TreeNode {
            public int val;
            public int count = 1;
            public TreeNode left, right;
            
            public TreeNode(int val) {
                this.val = val;
            }
        }
        
        public List<Integer> countSmaller(int[] nums) {
            List<Integer> res = new ArrayList<>();
            if(nums == null || nums.length == 0) {
                return res;
            }
            TreeNode root = new TreeNode(nums[nums.length - 1]);
            res.add(0);
            
            for(int i = nums.length - 2; i >= 0; i--) {
                int count = addNode(root, nums[i]);
                res.add(count);
            }
            
            Collections.reverse(res);
            return res;
        }
        
        private int addNode(TreeNode root, int val) {
            int curCount = 0;
            while(true) {
                if(val <= root.val) {
                    root.count++;                   // add the inversion count
                    if(root.left == null) {
                        root.left = new TreeNode(val);
                        break;
                    } else {
                        root = root.left;
                    }
                } else {
                    curCount += root.count;
                    if(root.right == null) {
                        root.right = new TreeNode(val);
                        break;
                    } else {
                        root = root.right;
                    }
                }
            }
            
            return curCount;
        }
    }

    Segment Tree:   超时TLE

    Time Complexity - O(n2), Space Complexity - O(n)

    public class Solution {
        private class SegmentTreeNode {
            public int start;
            public int end;
            public int max;
            public int min;
            public SegmentTreeNode left, right;
            
            public SegmentTreeNode(int start, int end) {
                this.start = start;
                this.end = end;
            }
        }
        
        private SegmentTreeNode root;
        
        public List<Integer> countSmaller(int[] nums) {
            List<Integer> res = new ArrayList<>();
            if(nums == null || nums.length == 0) {
                return res;
            }
            root = buildTree(nums, 0, nums.length - 1);
            
            for(int i = 0; i < nums.length; i++) {
                res.add(countSmaller(root, nums[i], i + 1, nums.length - 1));    
            }
            return res;
        }
        
        private int countSmaller(SegmentTreeNode node, int target, int lo, int hi) {  // search position to nums
            if(node == null) {
                return 0;
            }
            int mid = node.start + (node.end - node.start) / 2;
            if(node.start == lo && node.end == hi) {
                if(node.max < target) {
                    return hi - lo + 1;
                } else if(node.min > target) {
                    return 0;
                } else {
                    return countSmaller(node.left, target, lo, mid) + countSmaller(node.right, target, mid + 1, hi);
                }
            } else if (lo > mid) {
                return countSmaller(node.right, target, lo, hi);
            } else {
                return countSmaller(node.left, target, lo, mid) + countSmaller(node.right, target, mid + 1, hi);
            }
        }
        
        private SegmentTreeNode buildTree(int[] nums, int start, int end) {
            if(start > end) {
                return null;
            }
            SegmentTreeNode node = new SegmentTreeNode(start, end);
            if(start == end) {
                node.max = nums[start];
                node.min = nums[start];
            } else {
                int mid = start + (end - start) / 2;
                node.left = buildTree(nums, start, mid);
                node.right = buildTree(nums, mid + 1, end);
                node.max = Math.max(node.left != null ? node.left.max : Integer.MIN_VALUE, node.right != null ? node.right.max : Integer.MIN_VALUE);
                node.min = Math.min(node.left != null ? node.left.min : Integer.MAX_VALUE, node.right != null ? node.right.min : Integer.MAX_VALUE);
            }
            return node;
        }
    }

    Brute Force:  TLE超时

    Time Complexity - O(n2), Space Complexity - O(n)

    public class Solution {
        public List<Integer> countSmaller(int[] nums) {
            List<Integer> res = new ArrayList<>();
            if(nums == null || nums.length == 0) {
                return res;
            } 
            for(int i = 0; i < nums.length; i++) {
                int count = 0;
                for(int j = i + 1; j < nums.length; j++) {
                    if(nums[j] < nums[i]) {
                        count++;
                    }
                }
                res.add(count);
            }
            
            return res;
        }
    }

    Reference:

    https://leetcode.com/discuss/73256/mergesort-solution

    https://leetcode.com/discuss/73280/my-simple-ac-java-binary-search-code

    https://leetcode.com/discuss/73509/nlogn-time-space-mergesort-solution-with-detail-explanation

    https://leetcode.com/discuss/73762/9ms-short-java-bst-solution-get-answer-when-building-bst

    https://leetcode.com/discuss/74110/11ms-java-solution-using-merge-sort-with-explanation

    https://leetcode.com/discuss/73233/complicated-segmentree-solution-hope-to-find-a-better-one

    https://leetcode.com/discuss/74994/nlogn-divide-and-conquer-java-solution-based-bit-comparison

    https://leetcode.com/discuss/73917/accepted-c-solution-using-segment-tree

    https://leetcode.com/discuss/73803/easiest-java-solution

    https://leetcode.com/discuss/74961/7ms-java-solution-using-binary-indexed-tree

    https://leetcode.com/discuss/73739/java-o-nlogn-solution-using-bst-with-size-information

    https://leetcode.com/discuss/73558/15-ms-accepted-java-soln-using-mergesort

    https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/#prob

  • 相关阅读:
    数据量你造吗-JAVA分页
    编写高质量代码改善java程序的151个建议——[1-3]基础?亦是基础
    概率论快速学习03:概率公理补充
    概率论快速学习02:概率公理
    项目ITP(六) spring4.0 整合 Quartz 实现动态任务调度
    项目ITP(五) spring4.0 整合 Quartz 实现任务调度
    编写高质量代码改善java程序的151个建议——导航开篇
    概率论快速学习01:计数
    改善JAVA代码01:考虑静态工厂方法代替构造器
    Python快速学习10: 循环的对象及设计 (生活的规律)
  • 原文地址:https://www.cnblogs.com/yrbbest/p/5068550.html
Copyright © 2011-2022 走看看