LeetCode 215 Kth Largest Element in an Array

本文介绍两种高效算法来找出无序数组中的第K大元素。一种是通过快速排序改进的方法,利用partition操作缩小搜索范围,平均时间复杂度O(n),另一种是采用小顶堆(优先队列),维护大小为K的堆,堆顶即为第K大元素。

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,
Given [3,2,1,5,6,4] and k = 2, return 5.

Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.

思路:
  1. 选取数组合适的element作为pivot  (提高效率)
  2. 使用partition,elements<=pivot的放到pivot前,elements>=pivot的elements放到pivot后,pivot就放到了正确位置position。
  3. 缩小下次partition查找的范围。如果pivot的position比target大,那么扔掉pivot之后的elements,继续在pivot之前的elements里面找。反之,pivot的position小于target,扔掉pivot之前的elements,再pivot之后的elements里继续partition。这样不断缩小,一直到不能再缩小。
  4. nums[target] 就是 the kth distinct element。
1ms Java solution beats 99.1%.
	public int findKthLargest(int[] nums, int k) {
		int n = nums.length, target = n - k;
		quicksort(nums, 0, n - 1, target);
		return nums[n - k]; //nums[n - k]就是the kth largest element
	}


	private void quicksort(int[] nums, int start, int end, int target) {
		if (start >= end) return;
		int mid = start + (end - start) / 2;
		int pivot = choosePivot(nums[mid], nums[start], nums[end]);
		int i = start, j = end;
		while (i <= j) {
			while (nums[i] < pivot) i++;
			while (nums[j] > pivot) j--;
			if (i <= j) {
				if (nums[i] != nums[j]) swap(nums, i, j);
				i++;
				j--;
			}
		}
		if (target <= i - 1) quicksort(nums, start, i - 1, target);
		else quicksort(nums, i, end, target);
	}

	/**选取a,b,c三者的中位数*/
	private int choosePivot(int a, int b, int c) {
		int min = Math.min(a, Math.min(b, c));
		int max = Math.max(a, Math.max(b, c));
		return a - max + b - min + c;
	}

	private void swap(int[] nums, int i, int j) {
		int tmp = nums[i];
		nums[i] = nums[j];
		nums[j] = tmp;
	}
思路:
使用优先队列,维护size为k的小顶堆,堆顶的元素就是第k大的元素,而其余元素都比这个元素大。
9ms Java solution beats 66.46%.
	public int findKthLargest2(int[] nums, int k) {
		PriorityQueue<Integer> pq = new PriorityQueue<Integer>(k);
		for (int i = 0; i < nums.length; i++) {
			if (pq.size() < k) pq.offer(nums[i]);
			else if (nums[i] > pq.peek()) {
				pq.poll();
				pq.offer(nums[i]);
			}
		}
		return pq.peek();
	}
总结:一般快排的话,选取pivot的时候,不能每次只选第一个或者最后一个,可以选第一个或中间的或最后一个,最好选三者中排名第二大的;或者选取pivot之前,将无序数组进行shuffle也是不错的办法,但是效果还是前者更好。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值