练习一 : 排序数组(归并排序)
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)

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)

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];
}
}
}
转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/Boop_wu/article/details/159737460



