mirror of
https://github.com/ShusenTang/LeetCode.git
synced 2024-09-02 14:20:01 +00:00
Update 315. Count of Smaller Numbers After Self.md
This commit is contained in:
parent
ccbb8236e4
commit
24e72652f8
@ -23,11 +23,14 @@
|
|||||||
|
|
||||||
此题还可以用线段树/树状数组做,我们知道线段树和树状数组可以求前缀和,而这题可以转换成求前缀和。具体转换过程如下:
|
此题还可以用线段树/树状数组做,我们知道线段树和树状数组可以求前缀和,而这题可以转换成求前缀和。具体转换过程如下:
|
||||||
|
|
||||||
1. 我们先遍历一遍数组,确定数组中元素的最小值`MIN`和`MAX`,然后想象有一个大小为`MAX - MIN`的全0数组`arr`,在这个数组上构建线段树/树状数组;
|
1. 我们先遍历一遍数组,确定数组中元素的最小值`MIN`和`MAX`,然后想象有一个大小为`MAX - MIN`的全0数组`arr`,`arr[i]=j`表示`i+MIN`出现了j次。然后在这个数组上构建线段树/树状数组;
|
||||||
2. 然后从后往前遍历数组nums,将`arr[nums[i]]++`,更新线段树/树状数组,这样`arr`在区间`(nums[i], MAX]`的元素和即为`nums[i]`右侧它小的元素个数。
|
2. 然后从后往前遍历数组nums,将`arr[nums[i]-MIN]++`,表示出现次数加1,更新线段树/树状数组,这样就可很方便求得右侧比它小的元素个数。
|
||||||
|
|
||||||
时间复杂度O(nlogN),空间复杂度O(N),其中`N = MAX - MIN`;
|
时间复杂度O(nlogN),空间复杂度O(N),其中`N = MAX - MIN`;
|
||||||
|
|
||||||
|
关于线段树和树状数组可参考我的博客[Range Sum Query - Mutable (区间查询)](https://tangshusen.me/2019/11/17/range-sum-query-mutable/)
|
||||||
|
|
||||||
|
|
||||||
# C++
|
# C++
|
||||||
## 思路一
|
## 思路一
|
||||||
``` 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/)
|
[来源](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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
Loading…
Reference in New Issue
Block a user