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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM