空间复杂度:O(n)
发布时间:2025-06-24 18:24:56 作者:北方职教升学中心 阅读量:228
2.3 计算右侧小于当前元素的个数(hard)
题目链接:315. 计算右侧小于当前元素的个数
题目描述:
给你一个整数数组 nums
,按要求返回一个新数组 counts
。
O(n)
。它不仅展现了算法的美学,更体现了计算机科学中化繁为简的哲学。逆序对的产生方式可分为三种情况:
- 左数组中的元素逆序。
递归排序:
- 递归地对数组进行分治排序,并统计左右子数组中每个元素右侧更小的元素数量。
数组counts
有如下性质:counts[i]
的值是nums[i]
右侧小于nums[i]
的元素的数量。
临时数组的使用:
- 临时数组
tmp
存储每一轮合并结果,以确保排序结果被完整保留到下一轮递归。👍 点赞、
- 若
left[cur1] <= right[cur2]
,则将left[cur1]
添加到help
数组中。
递归终止条件:
- 当
left >= right
时停止递归,避免无效操作。
C++ 代码实现
classSolution{vector<int>ret;// 结果数组vector<int>index;// 记录元素的原始下标inttmpNums[100010];// 临时数组用于排序inttmpIndex[100010];// 临时数组用于记录索引排序public:vector<int>countSmaller(vector<int>&nums){intn =nums.size();ret.resize(n,0);// 初始化结果数组为0index.resize(n);// 初始化下标数组for(inti =0;i <n;i++){index[i]=i;// 初始时,索引与数组位置一一对应}mergeSort(nums,0,n -1);returnret;}voidmergeSort(vector<int>&nums,intleft,intright){if(left >=right)return;// 1. 分区intmid =(left +right)/2;// 2. 递归处理左右子区间mergeSort(nums,left,mid);mergeSort(nums,mid +1,right);// 3. 合并并统计逆序对intcur1 =left,cur2 =mid +1,i =0;while(cur1 <=mid &&cur2 <=right){if(nums[cur1]<=nums[cur2]){tmpNums[i]=nums[cur2];tmpIndex[i++]=index[cur2++];}else{// 当前左侧元素大于右侧元素,统计逆序对ret[index[cur1]]+=right -cur2 +1;tmpNums[i]=nums[cur1];tmpIndex[i++]=index[cur1++];}}// 处理剩余元素while(cur1 <=mid){tmpNums[i]=nums[cur1];tmpIndex[i++]=index[cur1++];}while(cur2 <=right){tmpNums[i]=nums[cur2];tmpIndex[i++]=index[cur2++];}// 拷贝回原数组for(intj =left;j <=right;j++){nums[j]=tmpNums[j -left];index[j]=tmpIndex[j -left];}}};
易错点提示
确保索引正确绑定:
- 在每次合并的过程中,索引数组
index
也需要同步排序,以保证结果数组ret
的统计准确。收藏与分享:如果觉得这篇文章对您有帮助,请点赞、通过不断划分,将一个复杂问题逐步拆解成若干规模更小的子问题,以递归方式求解,再将解合并,从而解决初始问题。
- 在每次合并的过程中,索引数组
归并排序过程可以分为两个步骤:
- 分:将数组一分为二,不断划分,直到每个子数组长度为1。
- 左右数组合并时的翻转对数量。
- 空间复杂度:
O(n)
,临时数组tmp
占用额外空间。期待这篇文章能为读者打开分治法的大门,让你在算法学习中游刃有余!以上就是关于【优选算法篇】分治乾坤,万物归一:在重组中窥见无声的秩序的内容啦,各位大佬有什么问题欢迎在评论区指正,或者私信我也是可以的啦,您的支持是我创作的最大动力!❤️