[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

分治 :

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

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

  • numscur1<=numscur2 时不产生新的逆序对 , 只需要排序
  • numscur1>numscur2 时产生逆序对 , 由于是升序排序 , 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];
        }
    }

}
相关推荐
罗西的思考8 小时前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
CSharp精选营10 小时前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
美团技术团队11 小时前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法
To_OC1 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode
To_OC1 天前
LC 208 实现 Trie 前缀树:曾被名字劝退,写完发现是送分题
javascript·算法·leetcode
BadBadBad__AK1 天前
线段树维护区间 k 次方和
c++·数学·算法·stl
_清歌2 天前
DSpark 深度解读:DeepSeek-V4 如何用「半自回归」把推理速度提升 85%
算法
统计实现局2 天前
SVD 的三步走:双对角化、Givens 收敛、排序
算法
躬行见万象2 天前
《VLA 系列》UniLab 强化训练 | G1 机器人 |复现
算法