剑指No.51_数组中的逆序对
- 题目:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例:输入: [7,5,6,4]
输出: 5
- 基于归并排序实现的解法
本文所实现的解法基于我之前写的关于归并排序中的代码归并排序,在聚合函数部分做了一些改动。详细的解释可以看剑指offer。
public class MySolution {
// 辅助数组
private int[] aux;
// 返回结果
private int result;
public int reversePairsWay(int[] nums){
aux = new int[nums.length];
mergeSort(nums, 0, nums.length - 1);
return result;
}
public void mergeSort(int[] nums, int low, int high){
if (low >= high)
return;
int middle = low + (high - low) / 2;
mergeSort(nums, low, middle);
mergeSort(nums, middle + 1, high);
merge(nums, low, middle, high);
}
// 以上部分与归并排序完全相同
public void merge(int[] nums, int low, int middle, int high){
// 这里由于要求指针从后往前移动,所以这样初始化左右子数组的指针
int i = middle;
int j = high;
// 给辅助数组赋值
for (int k = low; k <= high; k++){
aux[k] = nums[k];
}
// 从数组的高位开始填入
for (int k = high; k >= low; k--){
// 左数组添加完毕
if (i < low)
nums[k] = aux[j--];
// 右数组添加完毕
else if (j < middle + 1)
nums[k] = aux[i--];
// 左数组指针位置比右数组指针位置大
else if (aux[i] > aux[j]) {
// 关键:左比右大,说明存在逆序对,而存在几个就是j - middle个,因为右子数组中在aux[j]左边的都小于等于它,
// 所以这些元素都和aux[i]构成逆序对
result += (j - middle);
// 把更大的元素放在数组末尾
nums[k] = aux[i--];
}
else
nums[k] = aux[j--];
}
}
- 更新代码,输出结果且打印出数组中的逆序对
/**
* @Description:
* 归并应用:逆序对问题,在一个数组中,如果左边的数字比右边的数字大,则这两个数字构成一个逆序对,请打印所有逆序对,求出总数
* @Author: chong
* @Data: 2021/6/20 2:27 下午
*/
public class reversePairs {
int[] aux;
int res;
public int reversePairs(int[] nums) {
aux = new int[nums.length];
res = 0;
reversePairs(nums, 0, nums.length - 1);
return res;
}
public void reversePairs(int[] nums, int low, int high){
if (low >= high)
return;
int mid = low + ((high - low) >> 1);
reversePairs(nums, low, mid);
reversePairs(nums, mid + 1, high);
merge(nums, low, mid, high);
}
public void merge(int[] nums, int low, int mid, int high){
int left = low;
int right = mid + 1;
for (int i = low; i <= high; i++){
aux[i] = nums[i];
}
for (int i = low; i <= high; i++){
if (left > mid)
nums[i] = aux[right++];
else if (right > high)
nums[i] = aux[left++];
else if (aux[left] > aux[right]){
res += mid - left + 1;
for (int k = left; k <= mid; k++)
System.out.println("逆序对:[" + aux[k] + ", " + aux[right] + "]");
nums[i] = aux[right++];
}else
nums[i] = aux[left++];
}
}
@Test
public void test(){
int[] nums = {7, 5, 6, 4};
int res = reversePairs(nums);
System.out.println(res);
}
}