Total Accepted: 7919
Total Submissions: 26711
Difficulty: Hard
You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i]
is the number of smaller elements to the right of nums[i]
.
Example:
Given nums = [5, 2, 6, 1] To the right of 5 there are 2 smaller elements (2 and 1). To the right of 2 there is only 1 smaller element (1). To the right of 6 there is 1 smaller element (1). To the right of 1 there is 0 smaller element.
Return the array [2, 1, 1, 0]
.
针对这种问题:查找每个元素后与本元素一起满足一定条件的个数。虽然明显是O(N*N)的方式,仍然可以通过归并排序顺带计算,优化到O(nlogn)。同样使用这种思想的题目:leetcode : 327. Count of Range Sum : 连续和在指定区间内
这个题目针对前一半(有序)的每个元素计算后面一半(有序)里面比这个元素小的个数。这里有一个trick:设置一个变量累加针对x,后面一半比他小的数量preCount,那么比x大的元素y,一开始就要加上preCount(比x小的后面一半的数,一定比y小)。同时注意:归并排序后,虽然数组有序的,但是原始顺序变化了,计算每个元素数量需要找到他们的位置,因此需要记录每个元素的index。
public class Solution {
class numindexList{
public int num;
public int index;
public numindexList(int num,int index){
this.index=index;
this.num=num;
}
}
public void mergesort(ArrayList<numindexList> nums,ArrayList<Integer> count,int left,int right){
if(left>=right)
return;
int mid=(right+left)/2;
mergesort(nums, count, left, mid);
mergesort(nums, count, mid+1, right);
ArrayList<numindexList> temp=new ArrayList<numindexList>((right-left)/2+1);
for(int i=0;i<(right-left)/2+1;i++)
temp.add(i, nums.get(left+i));
int preCount=0;
int i,j,index;
for(i=mid+1,j=0,index=left;i<=right&&j<(right-left)/2+1;index++){
if(nums.get(i).num<temp.get(j).num){
nums.set(index, nums.get(i));
count.set(temp.get(j).index, count.get(temp.get(j).index)+1);
i++;
preCount++;
}
else {
nums.set(index, temp.get(j++));
if(j<(right-left)/2+1)
count.set(temp.get(j).index, count.get(temp.get(j).index)+preCount);
}
}
while(i<=right){
nums.set(index++, nums.get(i++));
}
boolean first=true;
while(j<(right-left)/2+1){
nums.set(index++, temp.get(j));
if(!first)
count.set(temp.get(j).index, count.get(temp.get(j).index)+preCount);
else {
first=false;
}
j++;
}
}
public ArrayList<Integer> countSmaller(int[] nums) {
ArrayList<Integer> count=new ArrayList<>(nums.length);
ArrayList<numindexList> numsList=new ArrayList<>();
for(int i=0;i<nums.length;i++){
numsList.add(new numindexList(nums[i], i));
count.add(0);
}
mergesort(numsList,count,0,nums.length-1);
return count;
}
}
这道题目还可以使用BST来做,有时间再学习吧。。。。。