这道题有两种方法
第一种方法容易理解,代码也比较好写,但是效率并不算高
首先我们要理解题目的要求,就是要求右侧小于当前元素的个数,再将它进行返回。
拿到这道题想到的就是,先将这个数据进行排序,从小到大,这时候就知道对应位置比它小的个数。
举个例子: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++;
}
}
}