Skip to content

Latest commit

 

History

History
executable file
·
157 lines (151 loc) · 5.55 KB

315. Count of Smaller Numbers After Self.md

File metadata and controls

executable file
·
157 lines (151 loc) · 5.55 KB

315. Count of Smaller Numbers After Self

Question

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:

Input: [5,2,6,1]
Output: [2,1,1,0] 
Explanation:
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.

Thinking:

  • Method 1: Slow, beats 18.69%

    • find the right closed index whose value is same as current one.
    • only need to calculate the value between these two and add the result of that index.
    class Solution {
        public List<Integer> countSmaller(int[] nums) {
            Map<Integer, Integer> map = new HashMap<>();
            int[] arr = new int[nums.length];
            for(int i = nums.length - 1; i>= 0; i--){
                if(map.containsKey(nums[i])){
                    arr[i] = map.get(nums[i]);
                }
                else{
                    arr[i] = -1;
                }
                map.put(nums[i], i);
            }
            int[] result = new int[nums.length];
            for(int i = nums.length - 1; i >= 0; i--){
                int count = 0;
                if(arr[i] == -1){
                    for(int j = i; j < nums.length; j++){
                        if(nums[i] > nums[j]) count++;
                    }
                    result[i] = count;
                }else{
                    for(int j = i; j < arr[i]; j++){
                        if(nums[i] > nums[j]) count++;
                    }
                    result[i] = count + result[arr[i]];
                }
            }
            List<Integer> res = new LinkedList<>();
            for(int n : result) res.add(n);
            return res;
        }
    }
  • Method 2: Use index and frequency array. slow, beats 6.23%

    • Example[5,6,2,1]
      • We sort the array in ascending order[1,2,5,6]
      • we use another map to save the corresponding index: [2, 3, 1, 0], we need to remove the duplicate values.
      • we traversal the array from the end to the beginning, once we meet a value, we add the frequency.
      • Then we sum the appear number from the end to current index.
     class Solution {
         public List<Integer> countSmaller(int[] nums) {
             LinkedList<Integer> result = new LinkedList<>();
             if(nums == null || nums.length == 0) return result;
             Map<Integer, Integer> map = new HashMap<>();
             int[] copy = Arrays.copyOf(nums, nums.length);
             Arrays.sort(nums);
             int count = 0;
             map.put(nums[nums.length - 1], count);
             for(int i = nums.length - 2; i >= 0; i--){
                 if(nums[i] != nums[i + 1]){
                     map.put(nums[i], ++count);
                 }
             }
             int[] freq = new int[count+1];
             for(int i = copy.length - 1; i >= 0; i--){
                 freq[map.get(copy[i])]++;
                 int appear = 0;
                 for(int j = count; j > map.get(copy[i]); j--){
                     appear += freq[j];
                 }
                 result.addFirst(appear);
             }
             return result;
         }
     }
    • Method 3: BST, Beats 99.02%
      • We create a Node and look into this node:
         private static class Node{
         int val;
         int count; // Number of current value.
         int leftCount;	// Number of left child Node for current node.
         Node left, right;
         public Node(int val){
             this.val = val;
             this.count = 1;
         }
      } ```
      • For a right child node, the number of values smaller than current value should be: node.leftCount + parent.count+ parent.leftCount, so here are three conditions:
        1. given value equals to node.val: we need to add node.count: node.count++;
        2. given value is smaller than current value:
          • left is null, create a new node and return 0
          • left is not null, return insert(node.left, val), means we recursively call the function.
        3. given value is bigger than current value:
          • right is null, create a new node and should return node.count + node.leftCount.
          • right is not null, return node.count + node.leftcount + insert(node.right, val).
       class Solution {
           private static class Node{
               int val;
               int count;
               int leftCount;
               Node left, right;
               public Node(int val){
                   this.val = val;
                   this.count = 1;
               }
           }
           public List<Integer> countSmaller(int[] nums) {
               LinkedList<Integer> result = new LinkedList<>();
               if(nums == null || nums.length == 0) return result;
               Node root = new Node(nums[nums.length - 1]);
               result.add(0);
               for(int i = nums.length - 2; i >= 0; i--){
                   result.addFirst(insert(root, nums[i]));
               }
               return result;
           }
           private int insert(Node node, int val){        
               if(val == node.val){
                   node.count ++;
                   return node.leftCount;
               }else if(val < node.val){
                   node.leftCount++;
                   if(node.left == null){
                       node.left = new Node(val);
                       return 0;
                   }else{
                       return insert(node.left, val);
                   }
               }else{
                   if(node.right == null){
                       node.right = new Node(val);
                       return node.count + node.leftCount;
                   }else return node.count + node.leftCount + insert(node.right, val);
               }
           }
       }