493. Reverse Pairs

题意:

Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].

这种不能破坏 i 和j “相对关系” 的情况去统计一些结果的题,都可以考虑merge sort. 

merge sort解法:
比如merge sort 中分解成2块 [5 8 7 6] | [2 1 3 4], 那么统计左边和右边符合条件的,
5: 2 1 --->2个
8: 2 1 3 --->3个
7 : 2 1 3 -->3个
6: 2 1 --> 2个
总共10个


Key point: merge sort 时 在merge 之前 左边 index 一定小于 右边index
当然真正merge sort 是 自底向上的, 所以在merge 之前左右都是排序好的。
整个过程:
1.先分解成: [5 8] [7 6] [2 1 ] [ 3 4 ]
2. 统计这里的count,
3. 然后merge 变成 [5 8 ] [6 7 ] and [1 2 ] [3 4 ]
4. 继续统计 count ([5 8 ] [6 7 ] ) and count([1 2 ] [3 4 ])
5. 再merge [5 6 7 8] and [1 2 3 4]
6. count([5 6 7 8] [1 2 3 4])
7. 最后Merge 成[1 2 3 4 5 6 7 8]
注意1. 每次在count 前 左右两边的数组已经排序好了
2. merge 之前左边数组 任意 left_index < right _index 只有merge 完后才会破坏这种index 关系, 所以要在merge 之前去count

//1 用BST 会 TLE
//2. 用 merge sort

public class Solution {
    public int reversePairs(int[] nums) {
       return merge_count(nums,0, nums.length-1);
    }
    
    private int merge_count(int[] nums, int start, int end){
        if(start<end){
            int mid = start + (end-start)/2;
            int count = merge_count(nums,start, mid) + merge_count(nums,mid+1,end);  // sub 数组的 
            
            //再统计当前准备merge的,注意此时左右已经排好序了,经过上面的merge,例如 left = [5 6 7 8]  right =[1 2 3 4]
            int j = mid+1;
            for(int i=start; i<=mid; i++){
                while(j<=end && nums[i] > (long)nums[j] *2)
                    j++;
                count += j- (mid+1);
            }
            
            merge(nums,start,mid,end);
            return count;
        }
        
         return 0;
    }
    
    // merge left = [1 2 5 8]  right =[3 4 6 9]
    private void merge(int[] nums, int start, int mid, int end){
        int[] tmp = new int[end-start+1];  //merge sort 需要的额外空间在此
        
        int i= start;
        int j= mid+1;    
        int k=0;
        //for(; i<mid && j<end; tmp[k++]=(arr[i]<arr[j]?arr[i++]:arr[j++]));
        while(i<=mid && j<=end){      
            if(nums[i] < nums[j]){
                tmp[k++] = nums[i];
                i++;
            }
            else{
                tmp[k++] = nums[j];
                j++;
            }
        }
        
        //处理merge 完剩余部分
        while(i<=mid){tmp[k++] = nums[i++];}
        while(j<=end) {tmp[k++] = nums[j++];}
        
        // 把tmp copy 进nums
        int s = start;
        for(int num: tmp){
            nums[s++] = num;
        }
        
    }

}

  

猜你喜欢

转载自www.cnblogs.com/keepAC/p/9828148.html