[Java 算法] 归并排序

练习一 : 排序数组(归并排序)

912. 排序数组 - 力扣(LeetCode)

java 复制代码
class Solution {
    int[] tmp;
    public int[] sortArray(int[] nums) {
        tmp = new int[nums.length];
        mergeSort(nums,0,nums.length-1);
        return nums;
    }
    public void mergeSort(int[] nums,int left,int right){
        if(left>=right) return;

        //划分区间
        int mid = (right+left)/2;

        //递归左右区间
        mergeSort(nums,left,mid);
        mergeSort(nums,mid+1,right);

        //合并两个有序数组
        
        int cur1 = left,cur2 = mid+1,i = 0;
        while(cur1<=mid&&cur2<=right){
            tmp[i++] = (nums[cur1]<nums[cur2])?nums[cur1++]:nums[cur2++];
        }
        while(cur1<=mid){
            tmp[i++] = nums[cur1++];
        }
        while(cur2<=right){
            tmp[i++] = nums[cur2++];
        }
        //还原回nums数组
        for(int j = left;j<=right;j++){
            nums[j] = tmp[j-left];
        }
    }
}

算法原理 : 归并排序(分治)

1.划分区间 : [left,mid] , [mid+1,right]

2.递归左右区间

2.合并两个有序数组 : 双指针 cur1 = left,cur2 = mid+1

3.拷贝回 nums 数组 , 范围 [left , right]

练习二 : 交易逆序对的总数

LCR 170. 交易逆序对的总数 - 力扣(LeetCode)

java 复制代码
class Solution {
    int[] tmp;
    int count;
    public int reversePairs(int[] nums) {
        tmp = new int[nums.length];
        mergeSort(nums,0,nums.length-1);
        return count;
    }
    public void mergeSort(int[] nums,int left,int right){
        if(left>=right) return ;
        int mid = (right+left)/2;
        mergeSort(nums,left,mid);
        mergeSort(nums,mid+1,right);
        int cur1 = left,cur2 = mid+1 ,i = 0;
        while(cur1<=mid&&cur2<=right){
            if(nums[cur1]<=nums[cur2]){
                tmp[i++] = nums[cur1++];
                
            }else {//nums[cur1]>nums[cur2]
                count+=mid-cur1+1;
                tmp[i++] = nums[cur2++];
            }
        }
        while(cur1<=mid) tmp[i++] = nums[cur1++];
        while(cur2<=right) tmp[i++] = nums[cur2++];
        for(int j = left;j<=right;j++){
            nums[j] = tmp[j-left];
        }
    }
}

算法原理 : 归并排序+统计

逆序对 : [5,4]

分治 :

  • 分 : 把数组不断劈成两半 , 直到上下一个元素 (一个元素天然有序) ;
  • 治 : 把两个排好的小区间 , 合并为一个大的有序区间

在上一道归并排序的基础上添加了新的合并规则 : 合并规则(升序) :

  • nums[cur1]<=nums[cur2] 时不产生新的逆序对 , 只需要排序
  • nums[cur1]>nums[cur2] 时产生逆序对 , 由于是升序排序 , cur1 的右边也比 cur2 大 , 所以在 cur1~mid 区间的数都可以和 cur2 组成新的逆序对 , 注意不能统计已经遍历过的区间 , 容易重复计算

练习三 : 计算右侧小于当前元素的个数

315. 计算右侧小于当前元素的个数 - 力扣(LeetCode)

java 复制代码
class Solution {
    int[] Index;
    int[] tmpIndex;
    int[] tmpNums;
    int[] count;
    public List<Integer> countSmaller(int[] nums) {
        
        count = new int[nums.length];
        Index = new int[nums.length];//和指针同时移动,绑定下标
        for(int i = 0;i<nums.length;i++){
            Index[i] = i;
        }

        tmpIndex = new int[nums.length];//拷贝下标
        tmpNums = new int[nums.length];//拷贝数组
        megerSort(nums,0,nums.length-1);
        List<Integer> ret = new ArrayList<>();
        for(int num: count){
            ret.add(num);
        }
        return ret;
    }
    public void megerSort(int[] nums,int left,int right){
        if(left>=right) return ;
        int mid = (left+right)/2;
        megerSort(nums,left,mid);
        megerSort(nums,mid+1,right);
        int cur1 = left,cur2 = mid+1,i = 0;
        while(cur1<=mid&&cur2<=right){
            if(nums[cur1]<=nums[cur2]){
                tmpNums[i] = nums[cur2];
                tmpIndex[i] = Index[cur2];//同时排序 , 存储的原nums[cur2] 位置的元素
                i++;
                cur2++;
            }else{//nums[cur1]>nums[cur2]
                int index = Index[cur1];
                count[index] +=right-cur2+1;
                tmpNums[i] = nums[cur1];
                tmpIndex[i++] = Index[cur1++];
            }
        }
        while(cur1<=mid){
            tmpNums[i] = nums[cur1];
            tmpIndex[i++] = Index[cur1++];
        }
        
        while(cur2<=right){
            tmpNums[i] = nums[cur2];
            tmpIndex[i] = Index[cur2];
            i++;
            cur2++;
        }
        //拷贝
        for(int j = left;j<=right;j++){
            nums[j] = tmpNums[j-left];
            Index[j] = tmpIndex[j-left];
        }
    }

}
相关推荐
罗湖老棍子2 小时前
维护序列(信息学奥赛一本通- P1551)(洛谷-P2023)
算法·线段树·区间修改区间查询·多重懒标记
今儿敲了吗2 小时前
49| 枚举排列
数据结构·c++·笔记·学习·算法
-凌凌漆-2 小时前
【C语言】大小端判断
linux·c语言·算法
ChoSeitaku2 小时前
NO.2|数据结构设计|日志封装|DeepSeel接入封装|全量返回实现测试|SSE|流式响应实现测试
java·jvm·数据结构
We་ct2 小时前
LeetCode 67. 二进制求和:详细题解+代码拆解
前端·数据结构·算法·leetcode·typescript
炽烈小老头2 小时前
【每天学习一点算法 2026/04/01】零钱兑换
学习·算法
Morwit2 小时前
【力扣hot100】 70. 爬楼梯
c++·算法·leetcode·职场和发展
yuanyuan2o22 小时前
你可能需要的算法思想——动态规划
数据结构·python·算法·动态规划
唯创知音2 小时前
WTK6900FC鼾声识别芯片:基于DNN-HMM算法的高性能鼾声识别检测处理方案
人工智能·算法·dnn·鼾声识别芯片·鼾声检测芯片