LeetCode[315]计算右侧小于当前元素的个数

难度:Hard

题目:

给你一个整数数组 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]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

 Related Topics

  • 树状数组
  • 线段树
  • 数组
  • 二分查找
  • 分治
  • 有序集合
  • 归并排序

重点!!!解题思路

明确解题思路:

        题中要求求出右侧小于当前元素的数量,如果将数组拆分开来,左右两边都是降序排列,如果当左边数组有一个值大于右边数组的其中一个值,那么就意味着比当前左边这个数小的元素有右边那个数到右边数组末尾那么多个,即题目可使用归并排序来解决。

源码+讲解:

    class Solution {
        class Data {  //因为你要记录每个值所对应得右边元素个数,hashmap太麻烦,我们直接封装一个内部类
            int ind, val, cnt;  //对应下标,值,右边对应得元素

            public Data(int ind, int val) {  //初始化
                this.ind = ind;
                this.val = val;
                cnt = 0;
            }
        }

        Data[] temp;  //归并排序的克隆数组

        public List<Integer> countSmaller(int[] nums) {
            temp = new Data[nums.length];
            Data[] data = new Data[nums.length];  //待排序数组
            for (int i = 0; i < nums.length; i++) {  //将每个元素封装到类中
                data[i] = new Data(i, nums[i]);
            }
            merge_sort(data, 0, data.length - 1);  //开始归并排序
            Arrays.sort(data, new Comparator<Data>() {  //当归并排序后,我们需要每个数组下标从小到大来输出,那么我们就需要一个小顶堆
                @Override
                public int compare(Data o1, Data o2) {
                    return o1.ind - o2.ind;
                }
            });
            List<Integer> res = new ArrayList<>();  //集合结果用来还原堆中的值
            for (Data datum : data) {
                res.add(datum.cnt);
            }
            return res;
        }

        //很基础的一个归并排序解法 如果有不懂得朋友 可以看看我前面发的题
        public void merge_sort(Data[] data, int l, int r) {
            if (l >= r) return;
            int mid = (l + r) >> 1;
            merge_sort(data, l, mid);
            merge_sort(data, mid + 1, r);
            int k = l, p1 = l, p2 = mid + 1;
            while (p1 <= mid || p2 <= r) {
                if (p2 > r || (p1 <= mid && data[p1].val > data[p2].val)) {
                    data[p1].cnt+=(r-p2+1);
                    temp[k++] = data[p1++];
                } else {
                    temp[k++] = data[p2++];
                }
            }
            for (int i=l;i<=r;i++) data[i]=temp[i];
        }
    }

 运行结果:

如果您还有什么疑问或解答有问题,可在下方评论,我会及时回复。

系列持续更新中,点个订阅吧,喜欢练习算法那就点个攒吧 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月亮被咬碎成星星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值