小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
思路
1.归并排序在merge的过程中会把两组数从小到大排序到一个数组中
2.在merge的过程中如果nums[p1]>nums[p2],那么就是满足前面一个数大于后面的数的情况, 而在p1 ~ mid这个范围上面的数也是大于nums[p2]的(因为原来p1所在的数组部分有序)。
3.所以实际上就是在归并排序的merge中记录满足题目要求的值。
if (nums[p1] > nums[p2]) {
res += (mid - p1 + 1);
}
代码
class Solution {
int res = 0;
public int reversePairs(int[] nums) {
if (nums == null || nums.length < 2) return 0;
mergeSort(nums);
return res;
}
public void mergeSort(int[] nums) {
mergeSort(nums, 0, nums.length - 1);
}
public void mergeSort(int[] nums, int left, int right) {
if (left < right) {
int mid = left + ((right - left) >> 1);
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
merge(nums, left, right, mid);
}
}
public void merge(int[] nums, int left, int right, int mid) {
//创建一个可以存放left ~ right的辅助数组
int[] temp = new int[right - left + 1];
int p1 = left;
int p2 = mid + 1;
int index = 0;//辅助变量给temp使用
while (p1 <= mid && p2 <= right) { //两个指针有一个走到终点退出
if (nums[p1] > nums[p2]) {
res += (mid - p1 + 1);
}
//哪个数小就用哪个数并且指针向后移动
temp[index++] = nums[p1] <= nums[p2] ? nums[p1++] : nums[p2++];
}
while (p1 <= mid) { //p1没有走完的情况
temp[index++] = nums[p1++];
}
while (p2 <= right) { //p2没有走完的情况
temp[index++] = nums[p2++];
}
//把值赋给原数组
for (int i = left; i <= right; i++) {
nums[i] = temp[i - left];
}
}
}