归并排序练习

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了归并排序练习相关的知识,希望对你有一定的参考价值。

力扣88. 合并两个有序数组
链接:https://leetcode-cn.com/problems/merge-sorted-array/

class Solution 
    public void merge(int[] nums1, int m, int[] nums2, int n) 
        //使用临时数组,先将数组排序到其中;
        int[] temp = new int[m+n];
        //临时数组的指针index;
        int index = 0;
        //数组1指针left 数组2指针right;
        int left  = 0;
        int right = 0; 
        //在不超出指针范围的情况内操作;
        while(left <m && right<n)
            if(nums1[left]<=nums2[right])
                temp[index++] = nums1[left++];
            else
                temp[index++] = nums2[right++];
            
        
        //若某个数组没有结束,则直接拼接;
        while(left<m)
            temp[index++] = nums1[left++];
        
        while(right<n)
            temp[index++] = nums2[right++];
        
        //数组内容复制到nums1;
        for(int i = 0;i<m+n;i++)
            nums1[i] = temp[i];
        
    


力扣剑指offer51题练习
剑指 Offer 51. 数组中的逆序对

在归并排序的过程中,第二段数组归并时 计算出逆序对的个数;
[逆序对,左边的数组元素 大于 右边的数组元素]

class Solution 
 //归并排序思想;
 int res =0;
 public int reversePairs(int[] nums) 
     int n = nums.length;
     if(n<1) return 0;
     //定义临时数组;
     int[] temp = new int[n];
     //调用方法;
     int res = reversePairs(nums,0,n-1,temp);
     return res;
 

 //在[left,right]区间完成分组排序任务,计算出逆序对;
 private int reversePairs(int[] nums,int left,int right,int[] temp)
     //递归终止条件;
     if(left == right)
         return 0;
     
     //分隔点;
     int mid = left +(right -left)/2;
     //递归计算左右的逆序对;
     int leftPair = reversePairs(nums,left,mid,temp);
     int rightPair = reversePairs(nums,mid+1,right,temp);
     //复制一份数组;
     for(int i = left;i<=right;i++)
         temp[i] = nums[i];
     
     //此处可优化;
     if(nums[mid]<=nums[mid+1])
         return leftPair + rightPair;
     

     //归并排序处理;
     int mergePair = mergeSort(nums,left,right,mid,temp);
     return leftPair + rightPair + mergePair; 
 

 //归并排序;
 private int mergeSort(int[] nums, int left,int right,int mid,int[] temp)
     int i = left;
     int j = mid+1;
     int resPair = 0;
     //定义出归并数组的索引 index;
     for(int index = left;index<=right;index++)
         //边界条件处理;
         if(i == mid+1)
             nums[index] = temp[j++];
         else if(j == right+1)
             nums[index] = temp[i++];
         else if(temp[i] <= temp[j])
             nums[index] = temp[i++];
         else
             nums[index] = temp[j++];
             //注意这里的逆序对计算时计算规则,
             //是第二部分数组合适时,此时的左边数组中剩余元素,
             //正好就是 中点mid-此时i的位置, 由于索引i会由0开始,则加1;
             resPair +=(mid - i)+1;
         
     
     return resPair;
 



力扣315题练习
315. 计算右侧小于当前元素的个数

类似于剑指51题;不过这里需要将逆序对的个数具体查找存储;

class Solution 
    public List<Integer> countSmaller(int[] nums) 
        List<Integer> list = new ArrayList<>();
        int n = nums.length;
        //类似于剑指51的逆序对问题,不过它要把逆序对拼接称为一个集合;
        //使用辅助索引数组;
        int[] indexArr = new int[n];
        int[] temp = new int[n];
        int[] res  = new int[n];
        //辅助数组初始化;
        for(int i=0;i<n;i++)
            indexArr[i]=i;
        
        //调用方法,在[0~n-1]区间内计算;
        countSmaller(nums,0,n-1,temp,indexArr,res);
        //将结果数组中的值存入到集合;
        for(int i=0;i<n;i++)
            list.add(res[i]);
        
        return list;
    

    //使用方法,在[left~right]区间内找到逆序对;
    private void countSmaller(int[] nums,int left,int right,int[] temp,int[] indexArr,int[] res)
        //递归终止条件;
        if(left == right)
            return;
        
        //分隔点;
        int mid = left +(right - left)/2;
        //分别递归;
        countSmaller(nums,left,mid,temp,indexArr,res);
        countSmaller(nums,mid+1,right,temp,indexArr,res);
        //优化提前退出;
        if(nums[indexArr[mid]]<=nums[indexArr[mid+1]])
            return;
        
        //归并排序,当然要把逆序对UC存入到结果数组;
        mergeSort(nums,left,right,mid,temp,indexArr,res);
    
    //归并排序;
    private void mergeSort(int[] nums,int left, int right,int mid,int[] temp,int[]indexArr,int[] res)
        //对临时数组赋值;
        for(int w = left;w<=right;w++)
            //注意临时数组其实放的是索引;
            temp[w] = indexArr[w];
        
        //两个数组的指针;
        int i = left;
        int j = mid+1;
        //排序数组的处理;
        for(int index = left;index<=right;index++)
            //边界条件处理;
            if(i ==  mid+1)
                //注意这里操作赋值的是索引;
                indexArr[index] = temp[j++];
            else if(j == right+1)
                indexArr[index] = temp[i++];
                //计算右侧后序数组的逆序对;
                res[indexArr[index]] += (right-mid);
            else if(nums[temp[i]]<=nums[temp[j]])
                indexArr[index] = temp[i++];
                //计算右侧后序数组的逆序对;
                res[indexArr[index]] += j -mid -1;
            else
                indexArr[index] = temp[j++];
            
        
    


力扣439题练习
493. 翻转对

class Solution 
    public int reversePairs(int[] nums) 
        int n = nums.length;
        if(n < 2) return 0;
        //使用临时数组;
        int[] temp = new int[n];
        //调用方法;
        return reversePairs(nums,0,n-1,temp);
    

    //在[left~right] 区间内计算;
    private int reversePairs(int[] nums,int left, int right, int[] temp)
        //递归结束条件;
        if(left == right)
            return 0;
        
        //分隔点;
        int mid = left +(right - left)/2;
        //左右递归;
        int leftPair = reversePairs(nums,left,mid,temp);
        int rightPair = reversePairs(nums,mid+1,right,temp);
       
        //复制数组;
        for(int i=left;i<=right;i++)
            temp[i] = nums[i];
        
        //归并排序中计算;
        int mergePair = mergeSort(nums,left,right,mid,temp);

        return leftPair + rightPair + mergePair;
    

    //归并排序;[left~right]区间
    private int mergeSort(int[] nums,int left,int right,int mid,int[] temp)
        //返回值;
        int res = 0;
        //分隔的两个数组指针;
        int i = left;
        int j = mid+1;
        //首先计算反转对;
        //在left-right范围内;
        while(i<=mid && j<=right)
            if((long)temp[i] >2* (long)temp[j])
                res += mid - i + 1;
                j++;
            else
                i++;
            
        

        //指针复位归并排序;
        i = left;
        j = mid+1;
        for(int index = left;index<=right;index++)
            //处理边界条件;
            if(i == mid+1)
                nums[index] = temp[j++];
            else if(j == right+1)
                nums[index] = temp[i++];
            else if(temp[i] <= temp[j])
                nums[index] = temp[i++];
            else
                nums[index] = temp[j++];
            
        
        return res;
    


以上是关于归并排序练习的主要内容,如果未能解决你的问题,请参考以下文章

归并排序

归并排序练习.

算法练习——归并排序

算法 - 归并排序

归并排序练习

快速排序算法 和 归并排序算法