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来做,有时间再学习吧。。。。。