LintCode-Kth Largest Element
Find K-th largest element in an array.
Note
You can swap elements in the array
Example
In array [9,3,2,4,8], the 3th largest element is 4
Challenge
O(n) time, O(1) space
Analysis:
We use Quick partition to perform the selection. We use the method of "median of medians", i.e., median of every group of 5 elements, to select the pivot. In this way, we can guarantee that the complexity in the worst case is still O(n).
Reference:
http://blog.csdn.net/v_JULY_v/article/details/6370650
http://blog.csdn.net/v_july_v/article/details/6431001
Solution:
1 class Solution { 2 //param k : description of k 3 //param numbers : array of numbers 4 //return: description of return 5 public int kthLargestElement(int k, ArrayList<Integer> numbers) { 6 return selectK(numbers,0,numbers.size()-1,k); 7 } 8 9 public void insertSort(ArrayList<Integer> numbers, int start, int end){ 10 for (int i=start;i<=end;i++){ 11 int key = numbers.get(i); 12 int ind = i-1; 13 while (ind>=start && numbers.get(ind)<key){ 14 numbers.set(ind+1,numbers.get(ind)); 15 ind--; 16 } 17 numbers.set(ind+1,key); 18 } 19 } 20 21 public void swap(ArrayList<Integer> numbers, int x, int y){ 22 int temp = numbers.get(x); 23 numbers.set(x,numbers.get(y)); 24 numbers.set(y,temp); 25 } 26 27 //This function selects the kth largest number in the range numbers[start...end]. 28 //For example, if start=8, end=11, k=2, we will select the 2nd largest number in the range numbers[8...11]. 29 //So in the code, we need be very carefull about the index of the kth largest number. 30 public int selectK(ArrayList<Integer> numbers, int start, int end, int k){ 31 if (end-start+1<=5){ 32 insertSort(numbers,start,end); 33 return numbers.get(start+k-1); 34 } 35 36 //Get the median of every group of 5 elements. 37 int pos = start; 38 int cur = start; 39 while (true){ 40 int curEnd = Math.min(cur+4,end); 41 //For even number, we pick up the later median, that is why there is plus one at last. 42 int median5 = selectK(numbers,cur,curEnd,(curEnd-cur+1)/2+1); 43 swap(numbers,pos,(curEnd+cur+1)/2); 44 pos++; 45 if (curEnd==end) break; 46 else cur = curEnd+1; 47 } 48 49 //Get the median of median5s, i.e., median of [start...pos-1]. 50 int median = selectK(numbers,start,pos-1,(pos-start)/2+1); 51 int mInd = start; 52 for (int i=start;i<=start+4;i++) 53 if (numbers.get(i)==median){ 54 mInd = i; 55 break; 56 } 57 58 59 //Use the median as the pivot to partition [start...end]. 60 swap(numbers,mInd,end); 61 int p1 = start, p2 = end-1; 62 while (p1<end && numbers.get(p1)>median) p1++; 63 while (p2>0 && numbers.get(p2)<median) p2--; 64 while (p1<p2){ 65 swap(numbers,p1,p2); 66 p1++; 67 p2--; 68 while (p1<end && numbers.get(p1)>median) p1++; 69 while (p2>0 && numbers.get(p2)<median) p2--; 70 } 71 swap(numbers,p1,end); 72 if (p1-start+1==k) 73 return numbers.get(p1); 74 else if (p1-start+1>k) 75 return selectK(numbers,start,p1-1,k); 76 else 77 return selectK(numbers,p1+1,end,k-(p1-start+1)); 78 } 79 80 81 82 };