• 315.计算右侧小于当前元素的个数


    给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

    示例 1:

    输入:nums = [5,2,6,1]
    输出:[2,1,1,0] 
    解释:
    5 的右侧有 2 个更小的元素 (2 和 1)
    2 的右侧仅有 1 个更小的元素 (1)
    6 的右侧有 1 个更小的元素 (1)
    1 的右侧有 0 个更小的元素
    示例 2:

    输入:nums = [-1]
    输出:[0]
    示例 3:

    输入:nums = [-1,-1]
    输出:[0,0]

    思路:归并排序

    数组中的元素进行归并排序时,在merge阶段,即对两个有序数组的合并过程中,每当执行 nums[i] = tmp[left] 时,就可以确定 tmp[left] 这个元素后面比它小的元素个数为 j - (mid+1)。 

    举个栗子:

    nums = [5,2,6,1] 

    归并排序树 :

                      1 2 5 6

                    /             \

                2  5            1  6

              /       \          /      \

           5          2      6         1

    采用归并排序(后序遍历),自底向上遍历

    1。单个结点5;

    2。单个结点2;

    3。5、2这两个有序数组合并。[5,2],low=0,mid=0,high=1取nums[i]=temp[right],此时不需要更新count,right++后right==high+1,nums[i]=temp[left],此时需要更新count,count[nums[i].second]=right-(mid+1)=1;                                        counts[1,0,0,0]

    4。单个结点6;

    5。单个结点1;

    6。6、1这两个有序数组合并,情况同3;                                    counts[1,0,1,0]

    7。2,5、1,6这两个有序数组合并。[2,5,1,6],low=0,mid=1,high=3,取nums[i]=temp[right],right

    ++,不需要更新count;之后取nums[i]=temp[left],left++,此时需要更新count,count=1,counts[1,1,1,0];再之后nums[i]=temp[left],继续更新count,count=1, counts[2,1,1,0]

    实际上,就是根据归并排序时,自底向上的顺序,分解子问题。在 merge阶段,当nums[lo..mid]nums[mid+1..hi] 两个子数组完成排序后,对于 nums[lo..mid] 中的每个元素 nums[i],去 nums[mid+1..hi] 中寻找符合条件的 nums[j] 。例如5右侧小于它的元素的个数,就是[5,2]中5右侧小于它的元素个数1,再加上[2,5,1,6]中5右侧小于它的元素个数1,两数相加,得到count=2。

    1. class Solution {
    2. public:
    3. vectorint,int>> arr;
    4. vector<int> counts;
    5. vectorint,int>> tmp;
    6. vector<int> countSmaller(vector<int>& nums)
    7. {
    8. counts.resize(nums.size());
    9. tmp.resize(nums.size());
    10. arr.resize(nums.size());
    11. for(int i=0;isize();i++)
    12. {
    13. arr[i]=make_pair(nums[i],i);
    14. }
    15. sort(arr,0,nums.size()-1);
    16. return counts;
    17. }
    18. void sort(vectorint,int>>&arr,int low,int high)
    19. {
    20. if(low>=high)
    21. return ;
    22. int mid=low+(high-low)/2;
    23. sort(arr,low,mid);
    24. sort(arr,mid+1,high);
    25. merge(arr,low,mid,high);
    26. }
    27. void merge(vectorint,int>>& arr,int low,int mid,int high)
    28. {
    29. for(int i=low;i<=high;i++)
    30. {
    31. tmp[i]=arr[i];
    32. }
    33. int left=low;
    34. int right=mid+1;
    35. for(int i=low;i<=high;i++)
    36. {
    37. if(left==mid+1)
    38. {
    39. arr[i]=tmp[right];
    40. right++;
    41. }
    42. else if(right==high+1)
    43. {
    44. arr[i]=tmp[left];
    45. left++;
    46. counts[arr[i].second]+=right-(mid+1);
    47. }
    48. else if(tmp[left]
    49. {
    50. arr[i]=tmp[left];
    51. left++;
    52. counts[arr[i].second]+=right-(mid+1);
    53. }
    54. else
    55. {
    56. arr[i]=tmp[right];
    57. right++;
    58. }
    59. }
    60. }
    61. };

  • 相关阅读:
    iOS UWB——NI框架部分类
    linux 进程管理相关内容
    springboot生成二维码的正确姿势-附视频附源码
    什么是集成测试?集成测试方法有哪些?
    在字节跳动和拼多多干了5年测试,熬夜总结出来的划水经验....
    JDK21更新内容:虚拟线程
    meta标签的妙用
    大佬指明方向!使用微服务的最佳实践以及如何避免采用微服务架构可能带来的复杂性陷阱
    6、Netty ByteBuf工作原理
    MySQL中的事务基础
  • 原文地址:https://blog.csdn.net/weixin_50437588/article/details/126202165