题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例
输入: [7,5,6,4]
输出: 5
算法思路
这道题考查的就是归并排序。在归并排序的过程中就可以计算出逆序对的总数。
归并排序框架
package com.sort;
import java.util.Arrays;
/**
* 归并排序
*
* @author: 小LeetCode~
**/
public class MergeSort {
public static void main(String[] args) {
int[] nums = {7, 8, 5, 1,3, 4, 9, 6};
System.out.println(Arrays.toString(nums));
mergesort(nums, 0, nums.length - 1);
System.out.println(Arrays.toString(nums));
}
private static void mergesort(int[] nums, int left, int right) {
if (left >= right) {
return;
}
int mid = (left+right)/2;
mergesort(nums, left, mid);
mergesort(nums, mid + 1, right);
merge(nums, left, mid, right);
}
private static void merge(int[] nums, int left, int mid, int right) {
int temp[] = new int[right-left+1];
int i = left;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
}else{
temp[k++] = nums[j++];
}
}
while(i<=mid) temp[k++] = nums[i++];
while(j<=right) temp[k++] = nums[j++];
//把临时数组赋值给原来的数组
for (int x = 0; x < temp.length ; x++) {
nums[left+x] = temp[x];
}
}
}
解出这道题的关键点在于 merge 过程中,如果 nums[ i ] > nums[ j ],那么这里存在一个逆序对,逆序对的数量为 mid - i + 1 个。因为当前的数字都构成逆序对了,那么当前后面的数字肯定也构成逆序对。
也就是说,直接套用归并排序框架,只需要改这一个地方就可以了。
代码实现
class Solution {
int res = 0;
public int reversePairs(int[] nums) {
MergerSort(nums, 0, nums.length - 1);
return res;
}
private void MergerSort(int[] nums, int left, int right) {
if (left >= right) return;
int mid = left + ((right - left) >> 1);
MergerSort(nums, left, mid);
MergerSort(nums, mid + 1, right);
Merge(nums, left, mid, right);
}
private void Merge(int[] nums, int left, int mid, int right) {
//临时数组
int[] temp = new int[right - left + 1];
int i = left;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
}else{
temp[k++] = nums[j++];
res += (mid-i+1);//关键点位置
}
}
while(i<=mid) temp[k++] = nums[i++];
while(j<=right) temp[k++] = nums[j++];
//把临时数组赋值给原先的数组
for (int x = 0; x < temp.length; x++) {
nums[left + x] = temp[x];
}
}
}