LeetCode 493. Reverse Pairs
2021-02-18 23:40:39 # leetcode # core problems # 剑指offer

Problem

剑指 Offer 51. 数组中的逆序对

1. 题目简述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

Example 1: 
输入: [7,5,6,4]
输出: 5

限制:
0 <= 数组长度 <= 50000

2. 算法思路

这道题有两种做法,一种是分治法,或者说归并排序;另一种是树状数组。这里只写第一种做法,第二种工作法待更新。

分治法(归并排序)

对于一个数组,我们先将其分为两段,也就是两个数组,l和r,然后分别进行排序。排好序后,我们进行遍历,两个指针和j,一开始指向l[0]和r[0],然后r指针不断向后移动,直到r[j] >= r[i],此时,从mid+1到j之间的所有数字和l[0]构成逆序对!然后i也向后移,直到mid。这样一层层分下去,和归并算法的思路一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Solution {
public int reversePairs(int[] nums) {
return mergeSort(nums, 0, nums.length - 1);
}

public int mergeSort(int[] nums, int l, int r) {
if (l >= r) {
return 0;
}

int mid = l + r >> 1, res = 0;
res += mergeSort(nums, l, mid) + mergeSort(nums, mid+1, r);

// 此时,左右两侧数组已经有序
for (int i = l, j = mid + 1; i <= mid; i++) {
while (j <= r && nums[i] > nums[j]) {
j++;
}
res += j - mid - 1;
}

// 开始归并排序
int[] temp = new int[r - l + 1];
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}

while (i <= mid) {
temp[k++] = nums[i++];
}
while (j <= r) {
temp[k++] = nums[j++];
}

for (int m = 0, n = l; m < temp.length; m++, n++) {
nums[n] = temp[m];
}

return res;
}
}