分治归并,LCR170交易逆序对的总数 力扣315.计算右侧小于当前元素的个数力扣493.翻转对

目录

LCR170交易逆序对的总数

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

力扣493.翻转对


LCR170交易逆序对的总数

我那个时候很疑问,左边和右边的怎么统计呢,我总不能说是光实现左右,不实现别的吧,于是我写了一下,边写边发现,左边的也可以慢慢拆分成一左一右的,因为假如有两个,那么他就分为一左一右,这样就清楚了,他计算时候,会把左边和右边统计上

class Solution {
    public int reversePairs(int[] record) {
       return mergeSort(record,0,record.length-1);
    }
    public int mergeSort(int[]record,int left,int right){
        if(left>=right){return 0; }
        int mid=(right+left)/2;
        int ret=mergeSort(record,left,mid)+mergeSort(record,mid+1,right);
        
        //合并两个有序数组[left,mid][mid+1,right]
        int []tmp=new int[right-left+1];
        int cur1=left;
        int cur2=mid+1;
        int k=0;
        while(cur1<=mid&&cur2<=right){
       if(record[cur1]<=record[cur2]){
        tmp[k++]=record[cur1++];
       }else{
        tmp[k++]=record[cur2++];
        ret+=mid-cur1+1;
       }
     }
     while(cur1<=mid)tmp[k++]=record[cur1++];
     while(cur2<=right)tmp[k++]=record[cur2++];
     k=0;
     for(int i=left;i<=right;i++){
        record[i]=tmp[k++];
     }
     return ret;
    }
}

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

我觉得从这里,你可以看到上面的题的影子,但是也有不同,不同的点在哪呢?

那就是他要求的是每个数对应的逆序对个数,所以你需要找到,其中的破局之道,即从上一个模版中,摘出核心,然后加一些他的东西,我刚开始是想用哈希表,但是又在想老师说的会不会有重复问题,所以不能使用哈希表,而是用下标保存索引。

class Solution {
    List<Integer>a;
    int[]index;
    int []ret;
    public List<Integer> countSmaller(int[] nums) {
    a=new ArrayList<>();
    ret=new int[nums.length];index=new int[nums.length];
    for(int i=0;i<nums.length;i++){
        index[i]=i;
    }
    mergeSort(nums,0,nums.length-1);
    for(int i=0;i<nums.length;i++){
        a.add(ret[i]);
    }
    return  a;
    }
    public void mergeSort(int []nums,int left,int right){
        if(left>=right)return;
        int mid=(left+right)/2;
        int []tmp=new int[right-left+1];
        int []index2=new int[right-left+1];
//[left,mid]  [mid+1,right]
        mergeSort(nums,left,mid);
        mergeSort(nums,mid+1,right);
        int cur1=left;
        int cur2=mid+1;
        int k=0;
        int p=0;
        while(cur1<=mid&&cur2<=right){
            if(nums[cur1]>nums[cur2]){
//这个是部分的索引,相当于未合并的两个小的。
                index2[k]=index[cur1];
//index是总体的索引,index[cur1]这个是存储的是对应位置,
                ret[index[cur1]]+=right-cur2+1;
                tmp[k++]=nums[cur1++];    
            }else{
                index2[k]=index[cur2];
                tmp[k++]=nums[cur2++];
            }
        }
        
        while(cur1<=mid){index2[k]=index[cur1]; tmp[k++]=nums[cur1++];}
        while(cur2<=right){index2[k]=index[cur2]; tmp[k++]=nums[cur2++];}
        k=0;
      for(int i=left;i<=right;i++){
//最后的合并
        index[i]=index2[k];
        nums[i]=tmp[k++];}
    }
}

力扣493.翻转对

​​​​​​​

分治,逆序对的思路,但是稍微有偏差,他的统计翻转对不能放在归并数组里面,

class Solution {
        int ret=0;
        int []index;
        public  int reversePairs(int[] nums) {
            index=new int[nums.length];
            for(int i=0;i<nums.length;i++){
                index[i]=i;
            }
            return mergeSort(nums,0,nums.length-1);
        }
        public int mergeSort(int[]nums,int left,int right){
            if(left>=right)return 0;
            int mid=(left+right)/2;
            mergeSort(nums,left,mid);
            mergeSort(nums,mid+1,right);
            int[]tmp=new int[right-left+1];
            int[]index2=new int[right-left+1];
            int cur1=left;
            int cur2=mid+1;
            int k=0;
          

            while(cur1<=mid&&cur2<=right){
//检查是不是符合翻转对不能条件
                if(index[cur1]<index[cur2]&&(long)nums[cur1]>(long)2*nums[cur2]){
                    ret+=right-cur2+1;
                    cur1++;}
//不符合则看下一个
                else{
                    cur2++;
                    }
                }
//指针重置
            cur1=left;
            cur2=mid+1;


            while(cur1<=mid&&cur2<=right){
                if(nums[cur1]>nums[cur2]){
                    index2[k]=index[cur1];
                    tmp[k++]=nums[cur1++];
                }else{
                    index2[k]=index[cur2];
                    tmp[k++]=nums[cur2++];
                }
            }

            while(cur1<=mid){index2[k]=index[cur1];tmp[k++]=nums[cur1++];}
            while(cur2<=right){index2[k]=index[cur2];tmp[k++]=nums[cur2++];}
            k=0;
            for(int i=left;i<=right;i++){
                index[i]=index2[k];
                nums[i]=tmp[k++];
            }
            return ret;
        }
}

题解与我写的有细微差别,就是在它相当于更快的进行一个while循环,但是实际的差别并不大,都是看cur2是否符合,假如符合的话就ret=right-cur2+1,假如不符合,就去cur2++看一看cur2比较小的那个能不能符合要求,假如都不符合要求,那么就直接退出循环

下面这个是保存cur1的区间去统计。因此不用写cur2,当然这里也对cur2进行了判断,假如直接可能越界的情况。

class Solution {
        int ret=0;
        int []index;
        public  int reversePairs(int[] nums) {
            index=new int[nums.length];
            for(int i=0;i<nums.length;i++){
                index[i]=i;
            }
            return mergeSort(nums,0,nums.length-1);
        }
        public int mergeSort(int[]nums,int left,int right){
            if(left>=right)return 0;
            int mid=(left+right)/2;
            mergeSort(nums,left,mid);
            mergeSort(nums,mid+1,right);
            int[]tmp=new int[right-left+1];
            int[]index2=new int[right-left+1];
            int cur1=left;
            int cur2=mid+1;
            int k=0;

            while(cur1<=mid&&cur2<=right){
                while(cur2<=right&&(long)nums[cur1]<=(long)2*nums[cur2])cur2++;
                if(cur2>right)break;
                    ret+=right-cur2+1;
                    cur1++;}
            cur1=left;
            cur2=mid+1;


            while(cur1<=mid&&cur2<=right){
                if(nums[cur1]>nums[cur2]){
                    index2[k]=index[cur1];
                    tmp[k++]=nums[cur1++];
                }else{
                    index2[k]=index[cur2];
                    tmp[k++]=nums[cur2++];
                }
            }

            while(cur1<=mid){index2[k]=index[cur1];tmp[k++]=nums[cur1++];}
            while(cur2<=right){index2[k]=index[cur2];tmp[k++]=nums[cur2++];}
            k=0;
            for(int i=left;i<=right;i++){
                index[i]=index2[k];
                nums[i]=tmp[k++];
            }
            return ret;
        }
}
相关推荐
低保和光头哪个先来1 分钟前
牛客算法简单题(JS版)
javascript·算法
王老师青少年编程2 分钟前
CSP/信奥赛C++刷题训练:经典前缀和例题(2):洛谷P6568:水壶
c++·算法·前缀和·csp·信奥赛
Elastic 中国社区官方博客11 分钟前
GraphQL 与 Elasticsearch 相遇:使用 Hasura DDN 构建可扩展、支持 AI 的应用程序
大数据·后端·elasticsearch·搜索引擎·全文检索·graphql·1024程序员节
·云扬·26 分钟前
WeakHashMap详解
java·开发语言·学习·1024程序员节
Dennis_nafla1 小时前
《MYSQL实战45讲》表数据删一半,为什么表文件大小不变?
mysql·1024程序员节
在人间负债^1 小时前
合约门合同全生命周期管理系统:企业智能合同管理的新时代
1024程序员节
CloudHu19891 小时前
2024年1024程序人生总结
1024程序员节
askah66442 小时前
无法启动此程序win10玩游戏找不到d3dx9_43.dll缺失的五种常用有效解决方法
windows·游戏·电脑·dll丢失·1024程序员节
~见贤思齐~4 小时前
记一次真实项目的性能问题诊断、优化(阿里云redis分片带宽限制问题)过程
redis·阿里云·云计算·1024程序员节
charlie1145141915 小时前
STM32 从0开始系统学习2
stm32·嵌入式硬件·c·1024程序员节·arm架构·寄存器映射