# [315. Count of Smaller Numbers After Self](https://leetcode.com/problems/count-of-smaller-numbers-after-self/) # 思路 给定一个数组,计算每个数字右边所有小于这个数字的个数。 ## 思路一、BST 我们从后往前遍历数组,如果某个数字的右边所有数字都是有序的,那么我们就可以使用二分计算该数字右边所有小于这个数字的个数,但是如何维护有序呢,如果使用插入排序,那每次维护有序数组的时间复杂度为O(n),所以总的复杂度为O(n^2),这和暴力法是一样的。 除了有序数组之外,二叉搜索树也可以进行二分。而每次向二叉树里插入元素的复杂度平均为O(logn),所以总的时间复杂度平均就为O(nlogn)。另外,每个节点需要存放以这个节点为根的树有多少个节点。 时间复杂度平均为O(nlogn),空间复杂度为O(n)。注意BST可能会退化成链表,这样时间复杂度就为O(n^2)了。 ## 思路二、归并排序 如果某个元素`nums[i]`大于其右边的某个元素`nums[j]`(j > i),那么这元素``就构成了一个逆序对,所以我们只需要求出以`nums[i]`为第一个元素的逆序对个数。 求逆序对最经典的方法就是分治,即归并排序。所以这题我们也可以用归并排序,只需要新增一行代码:在进行`merge`时,记录有多少个以`nums[i]`开头的逆序对。 时间复杂度为O(nlogn),空间复杂度为O(n)。 ## 思路三、线段树/树状数组 此题还可以用线段树/树状数组做,我们知道线段树和树状数组可以求前缀和,而这题可以转换成求前缀和。具体转换过程如下: 1. 我们先遍历一遍数组,确定数组中元素的最小值`MIN`和`MAX`,然后想象有一个大小为`MAX - MIN`的全0数组`arr`,在这个数组上构建线段树/树状数组; 2. 然后从后往前遍历数组nums,将`arr[nums[i]]++`,更新线段树/树状数组,这样`arr`在区间`(nums[i], MAX]`的元素和即为`nums[i]`右侧它小的元素个数。 时间复杂度O(nlogN),空间复杂度O(N),其中`N = MAX - MIN`; # C++ ## 思路一 ``` C++ struct BstNode{ int val, node_num; // node_num记录这棵树有多少节点 BstNode *left, *right; BstNode(int x): val(x), node_num(1), left(NULL), right(NULL){} }; class Solution { private: void BST_insert(BstNode *root, BstNode *node){ root -> node_num += 1; if(node -> val >= root -> val){ // 插入到右子树 if(root -> right) BST_insert(root -> right, node); else root -> right = node; } else{ // 插入到左子树 if(root -> left) BST_insert(root -> left, node); else root -> left = node; } } int count(BstNode *root, int target){ if(!root) return 0; if(root -> val < target) return 1 + (root -> left == NULL ? 0 : root -> left -> node_num) \ + count(root -> right, target); else return count(root -> left, target); } public: vector countSmaller(vector& nums) { vectorres(nums.size(), 0); if(nums.empty()) return res; BstNode *root = new BstNode(nums.back()); for(int i = nums.size() - 2; i >= 0; i--){ res[i] = count(root, nums[i]); BstNode *node = new BstNode(nums[i]); BST_insert(root, node); } return res; } }; ``` ## 思路二 ``` C++ class Solution { private: vectorres; void merge_sort(vector>&nums_with_idx, int l, int r){ if(l >= r) return; int mid = (l + r) / 2; merge_sort(nums_with_idx, l, mid); merge_sort(nums_with_idx, mid+1, r); merge(nums_with_idx, l, mid, r); } void merge(vector>&nums_with_idx, int l, int mid, int r){ vector>merged; int i = l, j = mid + 1; while(i <= mid && j <= r){ if(nums_with_idx[i].first <= nums_with_idx[j].first){ // 与普通归并排序相比新增的一步, 即记录逆序数: res[nums_with_idx[i].second] += j - mid - 1; // nums[i]大于nums[mid+1,...,j-1] merged.push_back(nums_with_idx[i++]); } else merged.push_back(nums_with_idx[j++]); } while(i <= mid){ res[nums_with_idx[i].second] += j - mid - 1; merged.push_back(nums_with_idx[i++]); } //while(j <= r) merged.push_back(nums_with_idx[j++]); for(int k = 0; k < merged.size(); k++) nums_with_idx[k+l] = merged[k]; } public: vector countSmaller(vector& nums) { vector>nums_with_idx; res = vector(nums.size(), 0); for(int i = 0; i < nums.size(); i++) nums_with_idx.push_back({nums[i], i}); merge_sort(nums_with_idx, 0, nums.size() - 1); return res; } }; ``` ## 思路三、树状数组 [来源](https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/solution/c-shu-zhuang-shu-zu-by-mryx/) ``` C++ class Solution { public: int* tree, n; int lowbit(int x){ return x&(-x); } void update(int pos, int delta){ while (pos <= n){ tree[pos] += delta; pos += lowbit(pos); } } int getSum(int pos){ int ret = 0; while (pos){ ret += tree[pos]; pos -= lowbit(pos); } return ret; } vector countSmaller(vector& nums) { n = nums.size(); vector ret(n); if (n == 0) return ret; int minn = -50000, maxx = 50000; for (int i=0;i=0;--i){ ret[i] = getSum(nums[i] - minn); update(nums[i]-minn+1, 1); } return ret; } }; ``` ## 思路三、线段树 [来源](https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/solution/c-xian-duan-shu-jie-fa-by-dufre/) ``` C++ struct SegmentTreeNode{ int start; int end; int count; SegmentTreeNode* left; SegmentTreeNode* right; SegmentTreeNode(int _start, int _end):start(_start),end(_end) { count = 0; left = NULL; right = NULL; } }; class Solution { public: SegmentTreeNode* build(int start, int end){ if (start > end) return NULL; SegmentTreeNode* root = new SegmentTreeNode(start, end); if (start == end){ root->count = 0; }else{ int mid = start + (end - start)/2; root->left = build(start, mid); root->right = build(mid+1, end); } return root; } int count(SegmentTreeNode* root, int start, int end){ if (root == NULL || start>end) return 0; if (start==root->start && end==root->end){ return root->count; } int mid = root->start + (root->end - root->start)/2; int leftcount = 0, rightcount = 0; if (start <= mid){ if (mid < end) leftcount = count(root->left, start, mid); else leftcount = count(root->left, start, end); } if (mid < end){ if (start <= mid) rightcount = count(root->right, mid+1, end); else rightcount = count(root->right, start, end); } return (leftcount + rightcount); } void insert(SegmentTreeNode* root, int index, int val){ if (root->start==index && root->end==index){ root->count += val; return; } int mid = root->start + (root->end - root->start)/2; if (index>=root->start && index<=mid){ insert(root->left, index, val); } if (index>mid && index<=root->end){ insert(root->right, index, val); } root->count = root->left->count + root->right->count; } vector countSmaller(vector& nums) { vector res; if (nums.empty()) return res; res.resize(nums.size()); int start = nums[0]; int end = nums[0]; for (int i=1; i=0; i--){ res[i] = count(root, start, nums[i]-1); insert(root, nums[i], 1); } return res; } }; ```