Update 315. Count of Smaller Numbers After Self.md

This commit is contained in:
ShusenTang 2020-08-12 19:43:48 +08:00 committed by GitHub
parent ccbb8236e4
commit 24e72652f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -23,11 +23,14 @@
此题还可以用线段树/树状数组做,我们知道线段树和树状数组可以求前缀和,而这题可以转换成求前缀和。具体转换过程如下:
1. 我们先遍历一遍数组,确定数组中元素的最小值`MIN`和`MAX`,然后想象有一个大小为`MAX - MIN`的全0数组`arr`,在这个数组上构建线段树/树状数组;
2. 然后从后往前遍历数组nums将`arr[nums[i]]++`,更新线段树/树状数组,这样`arr`在区间`(nums[i], MAX]`的元素和即为`nums[i]`右侧它小的元素个数。
1. 我们先遍历一遍数组,确定数组中元素的最小值`MIN`和`MAX`,然后想象有一个大小为`MAX - MIN`的全0数组`arr``arr[i]=j`表示`i+MIN`出现了j次。然后在这个数组上构建线段树/树状数组;
2. 然后从后往前遍历数组nums将`arr[nums[i]-MIN]++`表示出现次数加1更新线段树/树状数组,这样就可很方便求得右侧比它小的元素个数。
时间复杂度O(nlogN)空间复杂度O(N),其中`N = MAX - MIN`
关于线段树和树状数组可参考我的博客[Range Sum Query - Mutable (区间查询)](https://tangshusen.me/2019/11/17/range-sum-query-mutable/)
# C++
## 思路一
``` C++
@ -119,6 +122,71 @@ public:
}
};
```
## 思路三、线段树
``` C++
class SegTree{
private:
int n;
vector<int>tree; // 用一个长为2n的数组来表示树
public:
SegTree(vector<int>& nums) {
/* 对数组nums建线段树, 方便求sum(nums[i,...,j])以及更新nums[i]*/
n = nums.size();
tree = vector<int>(n*2, 0);
for(int i = 0; i < n; i++) // 建树
update(i, nums[i]);
}
void update(int i, int diff) {
/*更新操作: 将nums[i]的值加上diff*/
i += n; // 转换为线段树下标
while(i > 0){
tree[i] += diff;
i >>= 1;
}
}
int sumRange(int i, int j) {
/**求nums[i,...,j]的和*/
if(i > j) return 0;
i += n; j += n; // 转换为线段树下标
int res = 0;
for(; i <= j; i >>= 1, j >>=1){
if(i & 1) res += tree[i++]; // 是右孩子
if(!(j & 1)) res += tree[j--];
}
return res;
}
};
class Solution {
public:
vector<int> countSmaller(vector<int>& nums) {
int n = nums.size();
vector<int>res(n, 0);
if(!n) return res;
int min_num = nums[0], max_num = nums[0];
for(int &num: nums){
min_num = min(min_num, num);
max_num = max(max_num, num);
}
// nums_for_SegTree[i] = j 表示数字i出现了j次, 初始全0次
vector<int>nums_for_SegTree(max_num - min_num + 1, 0);
SegTree st = SegTree(nums_for_SegTree);
for(int i = n - 1; i >= 0; i--){
res[i] = st.sumRange(0, nums[i] - min_num - 1);
st.update(nums[i] - min_num, 1); // 出现次数+1, 更新树
}
return res;
}
};
```
## 思路三、树状数组
[来源](https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/solution/c-shu-zhuang-shu-zu-by-mryx/)
@ -164,108 +232,3 @@ public:
}
};
```
## 思路三、线段树
[来源](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<int> countSmaller(vector<int>& nums) {
vector<int> res;
if (nums.empty())
return res;
res.resize(nums.size());
int start = nums[0];
int end = nums[0];
for (int i=1; i<nums.size(); i++){
start = min(start, nums[i]);
end = max(end, nums[i]);
}
SegmentTreeNode* root = build(start, end);
for (int i=nums.size()-1; i>=0; i--){
res[i] = count(root, start, nums[i]-1);
insert(root, nums[i], 1);
}
return res;
}
};
```