315.计算右侧小于当前元素的个数
题目
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i]
的值是 nums[i]
右侧小于 nums[i]
的元素的数量。
示例:
输入: nums = [5,2,6,1]
输出:[2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素
提示:
-
0 <= nums.length <= 10^5
-
-10^4 <= nums[i] <= 10^4
思路
其实除了暴力没有特别好的思路,后来看了看别人的题解,自己又写了一遍。整体思路
对下标进行归并排序,并且在排序时记录下每个位置后面数字的个数详细思路
首先对整个数组进行归并。
在每个归并段内,通过比较nums[idx[i]]
来对idx[i]
进行归并排序。并且在排序出现:nums[idx[i]]>nums[idx[j]]
的时候,在idx[i]
这个位置对应的最终结果(也即比nums中下标为idx[i]
的元素右侧比这个元素大的元素个数)上面,加上该归并段内比nums[idx]
大的数的个数:e-j+1
。代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38class Solution {
public:
vector<int> countSmaller(vector<int>& nums) {
int n = nums.size();
vector<int> res(n,0),helper(n,0),idxs(n,0);
for(int i=0;i<n;i++) idxs[i] = i;
mergeAndSort(nums,res,idxs,helper,0,n-1);
return res;
}
void mergeAndSort(vector<int>& nums,vector<int>& res,vector<int>& idxs,vector<int>& helper,int s,int e){
if(s>=e) return;
int mid = s+(e-s)/2;
mergeAndSort(nums,res,idxs,helper,s,mid);
mergeAndSort(nums,res,idxs,helper,mid+1,e);
mergeAndCount(nums,res,idxs,helper,s,mid,e);
}
void mergeAndCount(vector<int>& nums,vector<int>& res,vector<int>& idxs,
vector<int>& helper,int s,int mid,int e){
for(int i=s;i<=e;i++){
helper[i] = idxs[i];
}
int i=s,j=mid+1,idx=s;
while(i<=mid&&j<=e){
if(nums[helper[i]]<=nums[helper[j]]){
idxs[idx++] = helper[j++];
}else{
res[helper[i]]+= e-j+1;
idxs[idx++]=helper[i++];
}
}
while(i<=mid){
idxs[idx++] = helper[i++];
}
while(j<=e){
idxs[idx++] = helper[j++];
}
}
};
315.计算右侧小于当前元素的个数