有一组数,对于其中任意两个数组,若前面一个大于后面一个数字,则这两个数字组成一个逆序对。请设计一个高效的算法,计算给定数组中的逆序对个数。
给定一个int数组A和它的大小n,请返回A中的逆序对个数。保证n小于等于5000。
测试样例:
输入:[1,2,3,4,5,6,7,0],8
返回:7
这道题如果用常规的遍历数组,对每个元素再进行数组的遍历,时间复杂度为O(n),肯定会超时,下面介绍一种时间复杂度为O(nlogn)。
/**
* 封装的一个数据类
*/
class Node {
// 值
int value;
// 比当前节点value大的节点数
int leftSize = 0;
Node left, right;
public Node(int value) {
this.value = value;
}
/**
* 将比自己大的节点放到前面,leftSize++,比自己小的,放到自己后面
*/
public void insert(int val) {
if (val > this.value) {
if (left != null) {
left.insert(val);
} else {
left = new Node(val);
}
leftSize++;
} else {
if (right != null) {
// 调用后面的节点的排序,随时保持leftSize的更新
right.insert(val);
} else {
right = new Node(val);
}
}
}
// 得到比自己大的节点的数量
public int getRank(int val) {
if (val == this.value) {
return leftSize;
} else if (val > this.value) {
return left.getRank(val);
} else {
return leftSize + 1 + right.getRank(val);
}
}
}
public class AntiOrder {
Node root = null;
public int count(int[] A, int n) {
int res = 0;
for (int i = 0; i < n; i++) {
res += helper(A[i]);
}
return res;
}
public int helper(int n) {
if (this.root == null) {
root = new Node(n);
return 0;
} else {
root.insert(n);
return root.getRank(n);
}
}
}