leetcode :315. Count of Smaller Numbers After Self :归并排序应用

315. Count of Smaller Numbers After Self

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值