这题 和 327. Count of Range Sum and  493. Reverse Pairs 几乎一样的解法,都属于hard 题, 可以用 merge sort, segment tree 和 BST 去求解。 注意如果自己去实现简单的BST, 在数组已经排序好的情况下 比 [1 2 3 4 5 6 ],会造成BST 退化成一个数组,从而造成TLE, 可以去用TreeSet 去做,TreeSet 用红黑树实现,从而避免BST退化。 

这里先介绍merge sort 解法:

题目大意: 需要统计数组中每个数 右边小于这个数的数字的个数。 

Example: Input: [5,2,6,1] Output: [2,1,1,0] 

既然是统计右边 需要不改变 统计过程中的相对位置, 那么merge sort 可以尝试,因为每次merge 过程中, 在“merge 前” 两个子数组中右边的index 一定比左边的index 小。 

这篇文章详细介绍了merge sort 的分解过程 https://www.cnblogs.com/DSNFZ/articles/7745785.html。 

详细算法: 

1.  [5]  [2] [6] [1] 先被分解成四个 自数组, 然后开始两两merge:

2.  [5] and [2], left side [5] 的index 一定比 right [2] 的小,  因为 2< 5, 所以 得到关系count(5) =1 , count(2) = 0 然后 merge 之后变成 [2 ,5]

3.  同step 2, merge [6] [1] ,先做merge 之前的关系统计, 得到 [1(6), 0(1) ] , merge 之后变成 [1 6 ]

4. 然后merge [ 2 5] 和 [1  6] ,注意此时 left [2 5] 的index 都比 [ 1 6] 小, 虽然 [2 5 ] 和[1 6] 的内部 index 关系已经被破坏,但已经在 2, 3 两步统计出 他们之前的关系 count(5) =1 count(2) =0, count(1) = 0 count(6) = 1

    因为 left 2> right 1, 所以 2的count 变成1 , count(2) = 1, 然后 left 5> right 1 所以  count(5) ++ = 2, 这样得到 所有 4个数之间的关系 count(1) = 0, count(2) =1, count(2) =1,  count(6) = 1 然后merge [2 5] 和[1 6] 得到最终Merge 后的数组 [1 2 5 6 ]

5. 至此算法结束,值得注意的时, 要求输出的结果是 没排序之前的  关系,然后经过merge sort 后 数组已经排好序了。 这里一个小trick, 本质上也是hash table 思想:   定义一个int[len] [2] nums_counts, 每个[2] 定义成  [num[i],i ]  这样不管怎么排序, i都表示最初的index, 然后把需要统计的 counts 单独 定义一个数组 int[] counts, 每次统计 counts 关系 时 都 用 counts[nums_count[1]]  来记录没排序前数组的统计。 

class Solution {
    public List<Integer> countSmaller(int[] nums) {
        if(nums == null || nums.length==0) return new ArrayList<Integer>();
        
        int[][] nums_count = new int[nums.length][2]; // [0] = nums[i], [1] = i, 因为返回结果需要和排序前一样,所以把nums[i]和i 合并一起。
        int[] counts = new int[nums.length];
        for(int i=0; i<nums.length; i++){
            nums_count[i][0] = nums[i];
            nums_count[i][1] = i;
        }    
        merge_count(nums_count, 0,nums_count.length-1,counts);  
        List<Integer> result = new ArrayList<>();
        for(int count: counts){
            result.add(count);
        }
         return result;
    }
    
    private void merge_count(int[][] nums, int s, int e, int[] counts){
        if(s<e){
            int mid = (s+e)/2;
            merge_count(nums,s,mid,counts);
            merge_count(nums,mid+1,e,counts);
            //[2,5]  [1,6]
            int j = mid+1;
            for(int i=s; i<=mid; i++){
                while(j<=e && nums[i][0] >nums[j][0]) j++; 
                counts[nums[i][1]] += j-(mid+1);
            }
            merge(nums,s,mid,e);
        }
        
        
    }
    
    private void merge(int[][] nums, int s, int mid, int e){
        int[][] tmp = new int[e-s+1][2];
        int i=s, j = mid+1;
        int k = 0;
        while(i<=mid && j<=e){
            if(nums[i][0] <= nums[j][0]) {
              tmp[k][0] = nums[i][0];
              tmp[k][1] = nums[i][1];  //每次在交换 [0] 时, 需要把[1] 表示的 index 同时交换,保证, nums[i] 和index 永远在一起。
              k++; i++;  
            }
            else {
              tmp[k][0] = nums[j][0];  
              tmp[k][1]   = nums[j][1];
              k++; j++;
            }
        }
        while(i<=mid) {
          tmp[k][0] = nums[i][0];  
          tmp[k][1] = nums[i][1];  
          k++; i++;  
            
        }
        while(j<=e){
          tmp[k][0] = nums[j][0];  
          tmp[k][1] = nums[j][1]; 
          k++; j++;  
        } 
        
        int t = s;
        for(int[] num: tmp){
            nums[t][0] = num[0];
            nums[t][1] = num[1];
            t++;
        }
        
    }
}

  

posted on 2018-10-22 04:10  KeepAC  阅读(141)  评论(0编辑  收藏  举报