面试问题 | TopK问题的三种解法 | O(nlogn) 以及 O(n) | 算法优化

TopK问题的三种解法 | O(nlogn) 以及 O(n)

topk问题是一道很经典的问题,里面包含了数据结构及算法的应用。brute force我们不谈,接下来说一下,如何通过O(nlogn)以及O(n)求解

1. 优先队列(弹k次)

首先把整个数组压入一个heap当中(java中的priority_queue), 再依次弹出K各元素。这个方法的好处是,由于我们只需要K的元素,因此我们不需要对所有的元素进行排序,优先队列就可以满足要求

2. DIvide and conquer 结合quicksort

打个比方,每一次quicksort,我们都能将某一特定元素T放置正确位置,并将数组分为L和R两部分,L的元素均小于T,R的元素均大于T。Recursive Case是T_index != K, 从而在R或者L中继续quicksort,直到我们选中的元素恰好在第K个。

这个算法的时间复杂度同样是O(nlogn)

3. Radix Sort(这是一个O(n)排序)

T(d*n), d是数字的位数。在位数很少的情况下,接近于线性复杂度。但是空间上会占用O(10 * n), 因此相当于时间换空间的做法,夸!

此上三个代码没什么好写的,都是基础,由于最近在学divide and conquer,因此下面只写一下第二个代码熟悉一下,可以直接复制到本地运行(JAVA)

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collections;
import java.util.Queue;

public class Top_K {
	void swap(int []nums, int i, int j) {
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}
	int QuickS(int []nums, int left,int mid, int right) {
		// swap the chosen element to the first one
		swap(nums, mid, left);
		// set the position pointer
		int pos_L = left, pos_R = right;
		while(pos_L < pos_R) {
			while(nums[pos_R] > nums[left]) {
				pos_R --;
				if(pos_R == pos_L) break;
			}
			while(nums[pos_L] <= nums[left]) {
				pos_L ++;
				if(pos_L == pos_R) break;
			}
			swap(nums, pos_L, pos_R);
		}
		swap(nums, left, pos_L);
		return pos_L;
	}
	private int divide(int k, int []nums, int left, int right) {
		int mid = (left + right) / 2;
		int pos = QuickS(nums, left, mid, right);
		// Base Case
		if(pos == k) return nums[pos];
		// Recursive Case
		if(pos < k) {
			return divide(k, nums, pos+1, right);
		}
		else {
			return divide(k, nums, left, pos-1);
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Top_K top_K = new Top_K();
		int K = 3;
		int nums[] = {1,5,4,10,-1,2};
		System.out.println(top_K.divide(nums.length-K+1, nums, 0, nums.length-1));
	}

}

你可能感兴趣的:(CS577,分治法)