目录
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; } }