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

posted @ 2015-12-23 01:25  YRB  阅读(4059)  评论(0编辑  收藏  举报