LeetCode.315. 计算右侧小于当前元素的个数(Java实现)

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

示例:

输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.
原题链接

思路:
题目的问题很简单,最容易想到的是暴力法,两个for循环依次判断即可,这样做的时间复杂度为O(n^2),数据量很大是会超时,不能AC。
仔细思考发现这个题和求数组的逆数对的题很相似,可以采用二路归并的思想解决,对于二路归并思想有些模糊的同学可以参考参考下面这两篇文章,
深入理解归并排序
二路归并实战
笔者认为这两篇是写的很不错的文章。
AC代码如下(有详细注释):


import java.util.Arrays;

public class Main {
    static int[] index;//存元素的下标
    static int[] temp;//归并排序需要用到的临时数组
    static int[] count;//对每个元素的统计
    public static void main(String[] args) throws IOException {
        int[] a = {5,2,6,1};
        index = new int[4];
        for(int i = 0;i<4;i++) index[i] = i;
        temp = new int[4];
        count = new int[4];
        merge(a,0,3);
        System.out.println(Arrays.toString(count));//结果为[2,1,1,0]
    }
    //注意:该方法名义上是要让nums数组升序,但实际交换的是index数组,这样便于统计每个元素的右边小于它的个数
    public static void merge(int[] nums,int left,int right){
        if(left == right) return;//一个元素肯定有序
        int mid = (left+right) >> 1;
        merge(nums,left,mid);//归并左子数组
        merge(nums,mid+1,right);//归并右子数组
        //要归并的子数组已然有序,就不需要统计了,直接返回
        if(nums[index[mid]]<=nums[index[mid+1]]) return;
        int i = mid,j = right,idx = right;
        while (i>=left && j>mid){
        	//统计
            if (nums[index[i]]>nums[index[j]]){//形如5,2,此时i值为0指向5,j值为1指向2
                count[index[i]] += j-mid;//5在原始数组nums的下标为0
                temp[idx--] = index[i--];
            }else temp[idx--] = index[j--];
        }
        while (i>=left) temp[idx--] = index[i--];
        while (j>mid) temp[idx--] = index[j--];
        //交换index数组,交换的是下标,原始数组nums不变,通过下标可以映射到数组nums的元素
        //虽然下标不是有序的,但通过下标映射到数组nums的值便是有序的
        for(i+=1;i<=right;i++){
            index[i] = temp[i];
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

b17a

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

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

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

打赏作者

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

抵扣说明:

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

余额充值