数组中的逆序对
解题思路
归并排序
归并排序将数组分割为若干有序的子段,并进行两两“向上”合并。
在一次归并过程中,第一段数组和第二段数组均为有序的,只需要统计归并过程中数组中==“失序”==的数组元素就能够得到逆序对数。假设p1
和p2
分别指向第一段数组A和第二段数组B的起始位置,且数组AB归并到数组C中。则存在两种不同的统计方式。
- 统计方式1:倘若 A [ p 1 ] < B [ p 2 ] A[p1]<B[p2] A[p1]<B[p2],选择 A [ p 1 ] A[p1] A[p1]作为下一个归并到数组C中的元素,易知 A [ p 1 ] > B [ m i d + 1 ⋯ p 2 − 1 ] A[p1]>B[mid+1\cdots p2-1] A[p1]>B[mid+1⋯p2−1],所以一共有 p 2 − ( m i d + 1 ) p2-(mid+1) p2−(mid+1)个逆序的数。
- 统计方式2:倘若 A [ p 1 ] > B [ p 2 ] A[p1]>B[p2] A[p1]>B[p2],选择 B [ p 2 ] B[p2] B[p2]作为下一个归并到数组C中段元素,易知 A [ p 1 ⋯ m i d ] > B [ p 2 ] A[p1 \cdots mid]>B[p2] A[p1⋯mid]>B[p2],所以一共有 m i d − p 1 + 1 mid-p1+1 mid−p1+1个逆序的元素
树状数组
使用二分查找+排序
来对数组进行离散化,使用桶来保存元素的信息,桶中保存元素出现的次数,前缀和即表示为所有小于该元素的个数。
从后向前进行操作,假设目前的遍历的元素为 a i a_i ai,利用前缀和,查找所有小于 a i a_i ai的个数,然后将 a i a_i ai加入到树状数组中去。
AC代码
归并排序
class Solution {
private static int[] temp = null;
public static int reversePairs(int[] nums) {
temp = new int[nums.length];
int res = mergeSort(nums, 0, nums.length - 1);
return res;
}
public static int mergeSort(int[] nums, int left, int right) {
if (left >= right)
return 0;
int mid = left + (right - left) / 2;
int leftPairs = mergeSort(nums, left, mid);
int rightPairs = mergeSort(nums, mid + 1, right);
int crossPairs = merge(nums, left, mid, right);
return leftPairs + crossPairs + rightPairs;
}
public static int merge(int nums[], int left, int mid, int right) {
int p1 = left, p2 = mid + 1;
for (int i = left; i <= right; i++) {
temp[i] = nums[i];
}
int cnt = left;
int ans = 0;
while (p1 <= mid && p2 <= right) {
if (temp[p1] <= temp[p2]) {
nums[cnt] = temp[p1];
p1++;
// 统计方法1
ans += p2 - (mid + 1);
} else {
nums[cnt] = temp[p2];
p2++;
// 统计方法2
// ans += (mid-p1+1);
}
cnt++;
}
if (p1 <= mid) {
while (p1 <= mid) {
nums[cnt++] = temp[p1++];
// 统计方法1
ans += (p2 - mid - 1);
}
}
if (p2 <= right) {
while (p2 <= right) {
nums[cnt++] = temp[p2++];
// 统计方法2
// ans += (mid-p1+1);
}
}
return ans;
}
}
树状数组
class Solution {
public static int reversePairs(int[] nums) {
int n = nums.length;
int[] temp = new int[n];
System.arraycopy(nums, 0, temp, 0, n);
Arrays.sort(temp);
for (int i = 0; i < n; i++) {
nums[i] = Arrays.binarySearch(temp, nums[i]) + 1;
}
BIT bit = new BIT(nums.length);
int ans = 0;
for (int i = n - 1; i >= 0; i--) {
ans += bit.query(nums[i] - 1);
bit.update(nums[i]);
}
return ans;
}
}
class BIT {
private int[] tree;
private int n;
BIT(int n) {
tree = new int[n + 1];
this.n = n;
}
public int lowbit(int x) {
return x & (-x);
}
public void update(int x) {
for (int i = x; i <= n; i += lowbit(i)) {
++tree[i];
}
}
public int query(int x) {
int res = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
res += tree[i];
}
return res;
}
}