力扣-计算右侧小于当前元素

这道题有两种方法

第一种方法容易理解,代码也比较好写,但是效率并不算高

首先我们要理解题目的要求,就是要求右侧小于当前元素的个数,再将它进行返回。

拿到这道题想到的就是,先将这个数据进行排序,从小到大,这时候就知道对应位置比它小的个数。

举个例子:5 2 6 1 ,将它进行排序就是1 2 5 6 ,比如5的话,比它小的是1 2;但是现在存在一个问题就是怎么知道1 2是否在5的右边;这时候还需要一个数组来确定是否满足在其的右边

这里我就用了一个二维数组,这道题就是int[4][2]的大小,第一个位置存入具体值,第二个位置存入它的位置的号,这道题就是

5 0 

2 1

6 2

1 3

再进行排序的时候就知道它的坐标,再根据坐标来判断是否满足题意 

class Solution {

    public List<Integer> countSmaller(int[] nums) {

    int []points=new int[nums.length];

        int length=nums.length;

        int [][]newIdea=new int[length][2];

        int jilu=0;

        for(int i=0;i<length;i++)

        {

            newIdea[i][0]=nums[i];

            newIdea[i][1]=i;

        }

        for(int i=0;i<length;i++)

        {

            for (int j=i+1;j<length;j++)

            {

                if(newIdea[i][0]>newIdea[j][0])

                {

                    int temp1=newIdea[i][0];

                    int temp2=newIdea[i][1];

                    newIdea[i][0]=newIdea[j][0];

                    newIdea[i][1]=newIdea[j][1];

                    newIdea[j][0]=temp1;

                    newIdea[j][1]=temp2;

                }

            }

        }

        for(int i=0;i<length;i++)

        {

            points[i]=newIdea[i][1];

        }

        List<Integer> list=new ArrayList();



        for(int i=0;i<length;i++)

        {

            for(int j=0;j<length;j++)

            {

                if(nums[i]==nums[points[j]])

                {

                    list.add(jilu);

                    break;

                }

                else if(i<points[j])

                {

                    jilu++;

                }

            }

            jilu=0;

        }

        return list;

    }

}

第二种方法,好理解但是代码不容易写,就是借助二叉搜索树,二叉搜索树就是左边小于右边的,在树的结构上定义count和res的两个属性,count属性就是记录当前节点的左子树有多少个,res就是目标结果集,当然属性也包括左右子树,大体思路就是,当新节点大于根节点,就到根节点的右端,此时它的res要更新为根节点的count+1,当为小于root对应的值就将根节点的count++;最后遍历完,得到res结果集

public class test4 {
    public static void main(String[] args) {
        int []nums={5,2,6,1};
        List<Integer>res = countSmaller(nums);
        System.out.println(res);
    }
    public static List<Integer> countSmaller(int []nums)
    {
        Integer [] res=new Integer[nums.length];
        Arrays.fill(res,0);
        Node root=null;
        for(int i=nums.length-1;i>=0;i--)
        {
            root=createNode(root,new Node(nums[i]),res,i);
        }
        return Arrays.asList(res);
    }
    public static Node createNode(Node root,Node node,Integer[] res,int i)
    {
        //count是它左边有几棵树
        //res是求的是最终的结果,它的左边的个数
        if(root==null)
        {
            root=node;
            return root;
        }
        //在它的左子树
        if(root.value>=node.value)
        {
            root.count++;
            root.left=createNode(root.left,node,res,i);
        }
        //它的右子树
        else
        {
            res[i]+=1+root.count;
            root.right=createNode(root.right,node,res,i);
        }
        return root;
    }
}
//考点就是二叉树
class Node{
    Node left;
    Node right;
    int value;
    int count;
    public Node(int value)
    {
        this.value=value;
    }
}

第三种方法就是归并排序的变形

基本思路就是归并排序,在合并的时候需要进行一些细节的操作;
举个例子就是
5 2 6 1
第一次结束后为2 5 1 6
具体说一下第二次的时候,在第二次合并的时候,2 与 5 默认加上右边的的个数,此时右边有1 6共两个,2 与5
的对应的结果就先加上2,在排序的时候,借助数组,temp是存入nums的值,temp2是为了存入下表,此时2与1进行比较,1小就将1加入数组,同时右指针向右移,2与6进行比较此时将2加入数组(同时下表数组也是要更新的),但此时2的结果也要更新,因为刚开始的时候默认右边都比左边大,减去右端到此时右指针的距离,依次进行下去

class Solution {
    int []res;
    int []index;
    int []temp;
    int []temp2;
      public List<Integer> countSmaller(int[] nums) {
        int len=nums.length;
        res=new int[len];
        index=new int[len];
        temp=new int[len];//临时数组是为了合并的时候,好进行排序
        temp2=new int[len];
        for(int i=0;i<len;i++)
        {
            res[i]=0;
            index[i]=i;
        }
        mergeSort(0,len-1,nums);
        List<Integer> list=new ArrayList<>();
        for(int i=0;i<len;i++)
        {
            list.add(res[i]);
        }
        return list;
    }
      public void mergeSort(int l,int r,int []nums)
    {
        if(l>=r)
        {
            return;
        }
       int m=(l+r)>>1;
       mergeSort(l,m,nums);
       mergeSort(m+1,r,nums);
       //上面完成了分,下面就是一个一个的和
       merge(l,r,m,nums);
    }
     public void merge(int l,int r,int m,int[]nums)
    {
        for(int i=l;i<m+1;i++)
        {
            res[index[i]]+=r-m;
        }
        int left=l,right=m+1;
        int jilu=0;
        while(left<=m&&right<=r)
        {
            if(nums[left]>nums[right])
            {
                temp[jilu]=index[right];
                temp2[jilu]=nums[right];
                jilu++;
                right++;
            }
            else
            {
                temp[jilu]=index[left];
                temp2[jilu]=nums[left];
                res[index[left]]-=r-right+1;;
                jilu++;
                left++;
            }
        }
        while(left<=m)
        {
            temp[jilu]=index[left];
            temp2[jilu]=nums[left];
            jilu++;
            left++;
        }
        while(right<=r)
        {
            temp[jilu]=index[right];
            temp2[jilu]=nums[right];
            jilu++;
            right++;
        }
        jilu=0;
        //temp就是临时的排好序的数组,下面就是要改变index的坐标了
        for(int i=l;i<=r;i++)
        {
            index[i]=temp[jilu];
            nums[i]=temp2[jilu];
            jilu++;
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值