剑指 Offer 51. 数组中的逆序对
此题数据范围为
[
0
,
50000
]
[0, 50000]
[0,50000],理论上说最多可能存在
50000
×
49999
2
=
1
,
249
,
975
,
000
\frac{50000\times 49999}{2}=1,249,975,000
250000×49999=1,249,975,000 个逆序对,因此用答案用 int
存储绰绰有余。
解法一:归并排序
归并排序的交换次数即为逆序对数目
class Solution {
int ans;
vector<int> tmp;
void mergeSort(vector<int> &a, int L, int R) {
if (L >= R) return;
int m = L+R >> 1;
mergeSort(a, L, m);
mergeSort(a, m+1, R);
int i = L, j = m+1, t = L;
while (i <= m && j <= R) {
if (a[j] < a[i]) {
tmp[t++] = a[j++];
ans += m+1-i;
}
else tmp[t++] = a[i++];
}
while (i <= m) tmp[t++] = a[i++];
while (--t >= L) a[t] = tmp[t];
}
public:
int reversePairs(vector<int>& nums) {
ans = 0;
int n = nums.size();
tmp.resize(n);
mergeSort(nums, 0, n-1);
return ans;
}
};
解法二:离散化+树状数组(或线段树)
不断将第 i 个数字按顺序放入树状数组中,每次查询前 i 个数字中大于该数的数字个数。
之所以要离散化,是因为数组中的数字大小可能是 1e9 级别的。
class BinaryIndexedTree {
vector<int> C;
public:
BinaryIndexedTree(int n) : C(n+1) {
}
void add(int x, int val) {
while (x < C.size()) {
C[x] += val;
x += x&-x;
}
}
int getSum(int x) {
int sum = 0;
while (x) {
sum += C[x];
x -= x&-x;
}
return sum;
}
};
class Solution {
public:
int reversePairs(vector<int>& nums) {
int n = nums.size();
vector<int> mp(n+1);
int t = 0;
for (int &num : nums) {
mp[++t] = num;
}
sort(mp.begin()+1, mp.begin()+1+t);
t = unique(mp.begin()+1, mp.begin()+1+t)-mp.begin()-1;
int ans = 0;
BinaryIndexedTree bit(n);
for (int &num : nums) {
num = lower_bound(mp.begin()+1, mp.begin()+1+t, num)-mp.begin();
ans += bit.getSum(n)-bit.getSum(num);
bit.add(num, 1);
}
return ans;
}
};
解法三:红黑树(插入和查询)
维护树的 s i z e size size 信息可快速查询比 n u m num num 大的数字的个数.
n n n 次查询,每次查询时间复杂度 O ( log n ) O(\log n) O(logn) ,总时间复杂度 O ( n log n ) O(n\log n) O(nlogn).
enum color_t {red, black};
class RedBlackTree {
struct node {
node *left, *right, *parent;
color_t color;
int val;
int size;
};
node *nil;
node *root;
// 创建一个size为1的红色节点
node* createNode(int x, node *parent) {
node *t = new node;
t->color = red;
t->parent = parent;
t->left = t->right = nil;
t->val = x;
t->size = 1;
return t;
}
void rotateLeft(node *z) {
node *p = z->parent;
node *y = z->right;
// 处理p的指针域
if (p == nil) root = y;
else if (z == p->left) p->left = y;
else p->right = y;
// 处理z的指针域
z->parent = y;
z->right = y->left;
y->left->parent = z;
// 处理y的指针域
y->parent = p;
y->left = z;
// 维护节点数据
y->size = z->size;
z->size -= y->right->size + 1;
}
void rotateRight(node *z) {
node *p = z->parent;
node *x = z->left;
// 处理p的指针域
if (p == nil) root = x;
else if (z == p->left) p->left = x;
else p->right = x;
// 处理z的指针域
z->parent = x;
z->left = x->right;
x->right->parent = z;
// 处理x的指针域
x->parent = p;
x->right = z;
// 维护节点数据
x->size = z->size;
z->size -= x->left->size + 1;
}
void fixup(node *z) {
node *p, *q;
while (z->parent->color != black) { // z的父节点是红色才会导致冲突
p = z->parent;
if (p == p->parent->left) {
q = p->parent->right;
if (q->color == red) { // case1: parent and uncle both red
p->color = q->color = black;
p->parent->color = red;
z = z->parent->parent;
continue;
}
if (z == z->parent->right) { // case2: uncle is black and z is right
z = z->parent;
rotateLeft(z);
}
z = z->parent->parent; // case3: uncle is black and z is left
rotateRight(z);
swap(z->color, z->parent->color);
break;
}
else {
q = p->parent->left;
if (q->color == red) { // symmetric case1: parent and uncle both red
p->color = q->color = black;
p->parent->color = red;
z = z->parent->parent;
continue;
}
if (z == z->parent->left) { // symmetric case2: uncle is black and z is left
z = z->parent;
rotateRight(z);
}
z = z->parent->parent; // symmetric case3: uncle is black and z is right
rotateLeft(z);
swap(z->color, z->parent->color);
break;
}
}
root->color = black;
}
public:
RedBlackTree() {
nil = new node;
nil->color = black;
nil->size = 0;
root = nil;
}
~RedBlackTree() {
// 后序遍历析构红黑树
node *z = root;
node *tmp = nullptr; // 记录最后析构的节点
while (z != nil) {
while (z->left != nil) z = z->left; // 有左孩子就遍历左子树,递归返回时遍历该节点
if (z->right != nil) z = z->right; // 没有左孩子但有右孩子
else { // 叶节点开始回溯
do {
// cout << z->val;
tmp = z;
z = z->parent;
delete tmp;
if (z == nil) break;
} while (z->right == tmp || z->right == nil);
if (z != nil) z = z->right;
}
}
delete nil;
}
void insert(int x) {
node *p = nil, *t = root;
while (t != nil) {
p = t;
++t->size;
if (x < t->val) t = t->left;
else t = t->right;
}
node *px = createNode(x, p);
if (p == nil) root = px;
else if (x < p->val) p->left = px;
else p->right = px;
fixup(px);
}
int countBigger(int x) {
node *p = root;
int tot = 0;
while (p != nil) {
if (p->val <= x) p = p->right;
else {
tot += p->right->size + 1;
p = p->left;
}
}
return tot;
}
};
class Solution {
public:
int reversePairs(vector<int>& nums) {
int ans = 0;
RedBlackTree rbt;
for (int num : nums) {
ans += rbt.countBigger(num);
rbt.insert(num);
}
return ans;
}
};