给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
哇的一声就哭了出来,这其实是逆序对的变型。
归并排序的基础上加上一个小小的统计就完成任务了。
值得学习的是分治法解决问题的思路。
将原问题分解成了两个子问题,并且分解子问题后还可以根据子问题合并出原问题的解。
毕竟对于左半部分的每个元素的来说,在只考虑右半部分的元素中,右半部分元素是否有序是无关紧要的,而且如果有序的话,更方便。
那么问题就可以通过分治法来解决了。
这里还有一个小技巧,就是通过对索引数组进行排序,来方便的找到归并排序中当前元素对应的原数组元素。就像是一个指针数组一样,根据指针指向的元素的值来修改指针的相对位置。
代码
class Solution {
public:
void merge(vector<int>& nums, vector<int>& index, vector<int>& tmp, int left, int right, vector<int>& ans) {
if (left >= right) return;
int mid = (left + right) / 2;
merge(nums, index, tmp, left , mid, ans);
merge(nums, index, tmp, mid + 1 , right, ans);
int l = left, r = mid + 1,i = left;
while (l <= mid || r <= right) {
if (r > right || (l <= mid && (nums[index[l]] <= nums[index[r]]))) {
tmp[i++] = index[l];
ans[index[l]] += (r - mid - 1);
l++;
} else {
tmp[i++] = index[r++];
}
}
for (int i = left; i <= right; i ++) index[i] = tmp[i];
}
vector<int> countSmaller(vector<int>& nums) {
int N = nums.size();
vector<int> index (N), tmp (N), ans (N, 0);
for (int i = 0; i < N; i++) index[i] = i;
merge(nums, index, tmp, 0, N - 1, ans);
return ans;
}
};