题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:输入: [7,5,6,4]
输出: 5
限制:0 <= 数组长度 <= 50000
思路一:
暴力解题:依题意,我们可以用双层for循环累计求和。
java代码:
class Solution {
public int reversePairs(int[] nums){
int count = 0;
for(int i=0;i<nums.length-1;i++){
for(int j = i+1;j<nums.length;j++){
if(nums[i]>nums[j]){
count++;
}
}
}
return count;
}
}
这是一道面试题,答案不可能这么简单。运行后会发现,当数据过大,会超时。
此种方法被pass掉。
思路二:
为了解决这个问题,我们需要设想这样一个场景。
这道题是要我们输出逆序数组对,那么我们怎样实现这个方式呢,答案是采用分而治之的思想,既然它要我们找逆序数对,我们不妨采用排序算法在排序过程中统计逆序数对。
归并排序实现逆序数对的统计
首先,我们需要了解什么是归并排序,它的思想是什么。
归并排序是一种典型的分治策略。
它包含这样三个步骤:
分解: 待排序的区间为 l, r,令 m = (l+r)/2,我们把 l, r 分成 [l, m ]和 [m + 1, r],采用递归不断分解。
解决: 使用归并排序递归地排序两个子序列
合并: 把两个已经排好序的子序列 [l, m] 和 [m + 1, r] 合并起来
这里借用网上的图来给大家分析:
首先我们需要采用递归来把数组给划分成最小单元。然后排序进行合并。
这里我们对拆分的数组进行合并,原理是开辟一个新的数组,将分散的2个有序数组进行比较并存入新数组中,最后返回这个新数组。
了解了归并排序,我们就可以在此基础上对我们这一题进行求解。由图我们可以看出,我们在合并的过程中进行统计逆序数对。只要第一个数组的元素大于第二个数组的元素,我们就可以进行统计。
统计公式为:count = mid-i+1
java代码:
public int reversePairs(int[] nums) {
int ret = 0;
int len = nums.length;
//判空操作
if(len<2){
return ret;
}
return mergeSort(nums, 0, nums.length - 1);
}
private int mergeSort(int[] nums, int left, int right) {
if (left >= right) {
return 0;
}
//拆分
int mid = (left+right)/2;
int leftPairs = mergeSort(nums, left, mid);
int rightPairs = mergeSort(nums, mid + 1, right);
//归并
int crossPairs = merge(nums, left, mid, right);
//将归并的所有结果汇总返回
return leftPairs+ rightPairs + crossPairs;
}
private int merge(int[] nums, int left, int mid, int right) {
//指向第一个数组指针
int i = left;
//指向第二个数组指针
int j = mid + 1;
int k = 0;
//计数
int count = 0;
//开辟新数组存放合并数组
int res[] = new int[right - left + 1];
//开始合并
while (i <= mid && j <= right) {
//如果j位置小于i位置,那么j位置小于i位置后所有的左半边的数
if (nums[i] > nums[j]) {
count += mid - i + 1;
res[k++] = nums[j++];
}else{
res[k++] = nums[i++];
}
// res[k++] = nums[i] <= nums[j] ? nums[i++] : nums[j++];
}
//合并剩下的数组
while (i <= mid) {
res[k++] = nums[i++];
}
while (j <= right) {
res[k++] = nums[j++];
}
//将值赋值回原数组
for (int m = 0; m < res.length; m++) {
nums[left + m] = res[m];
}
return count;
}
如若对此题还未理解,欢迎私信博主。或者是参考力扣官方题解:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/shu-zu-zhong-de-ni-xu-dui-by-leetcode-solution/
归并算法是一个经典算法,博主提醒小伙伴们务必掌握!