Get the K-th largest element in an array

How to get an array in O(n) such as {9, 1, 2, 8, 7, 3, 6, 4, 3, 5, 0, 9, 19, 39, 25, 34, 17, 24, 23, 34, 20} which has the largest K element?

We can use the partition method similar to fast row to limit the K-th largest element to the left or right of the array, and recursively calculate.

 

My Java code is implemented as follows:

 1 package com.structure.sort;
 2 
 3 /**
 4  * @author zhangxingrui
 5  * @create 2019-01-27 22:52
 6  **/
 7 public class QuickSort {
 8 
 9     public static void main(String[] args) {
10         int[] numbers = {9, 1, 2, 8, 7, 3, 6, 4, 3, 5, 0, 9, 19, 39, 25, 34, 17, 24, 23, 34, 20};
11 //        int[] numbers = {3,1,2};
12         // Fast sorting is realized by recursion. It is important to find the end condition of recursion (otherwise, stack exception is easy to occur)
13         // Recurrence formula: quickSort(p...r) = merge(p, q - 1) + merge(q+1, r)
14         // End condition: p >= r
15         /*quickSort(numbers, 0, numbers.length - 1);
16         for (int number : numbers) {
17             System.out.println(number);
18         }*/
19 
20         int k = getK(4, numbers, 0, numbers.length - 1);
21         System.out.println(k);
22     }
23 
24     private static void quickSort(int[] numbers, int p, int r){
25         if(p >= r)
26             return;
27         int q = partition(numbers, p, r, false);
28         quickSort(numbers, p, q - 1);
29         quickSort(numbers, q + 1, r);
30     }
31 
32     /**
33      * @Author: xingrui
34      * @Description: partition
35      * @Date: 23:13 2019/1/27
36      */
37     private static int partition(int[] numbers, int p, int r, boolean isAsc){
38         int k = numbers[r];
39         int i = p;
40 
41         if(isAsc){
42             for (int j = p; j <= r; ++j) {
43                 if(numbers[j] < k){
44                     int temp = numbers[i];
45                     numbers[i] = numbers[j];
46                     numbers[j] = temp;
47                     i++;
48                 }
49             }
50             numbers[r] = numbers[i];
51             numbers[i] = k;
52             return i;
53         }else{
54             for (int j = p; j <= r; ++j) {
55                 if(numbers[j] > k){
56                     int temp = numbers[i];
57                     numbers[i] = numbers[j];
58                     numbers[j] = temp;
59                     i++;
60                 }
61             }
62             numbers[r] = numbers[i];
63             numbers[i] = k;
64             return i;
65         }
66 
67     }
68 
69     /**
70      * @Author: xingrui
71      * @Description: Get the K-th largest element
72      * @Date: 23:15 2019/1/29
73      */
74     private static int getK(int k, int[] numbers, int p, int r){
75         int q = partition(numbers, p, r, false);
76 
77         if(q + 1 == k)
78             return numbers[q];
79 
80         if(q + 1 > k){
81             return getK(k, numbers, p, q - 1);
82         }else{
83             return getK(k, numbers, q + 1, r);
84         }
85     }
86 
87 }

The principle is that we first take any number as the number of partitions, put the number greater than it on its left, and the number less than it on its right.

Suppose we have array[p...r], then after the first partition, there are three parts of array[p...q-1], q, array[q+1...r]. If we want to take the third largest element,

Then compare 3 with q+1,

If 3==q+1, then there are only two elements in array[p...q-1] and they are all > array[q], while array[q+1,r] are < Q, so array[q]

Is the third element;

If 3 > Q + 1, there is only one element in array[p...q-1], so we need to find it in array[q+1...r];

If 3 < Q + 1, there are three elements in array[p...q-1], so we need to find them in array[p...q-1].

 

In this way, only half of the array in the partition will be found each time: n/2 + n/4 + n/8 + - until the interval is reduced to 1, then 2n - 1 will be obtained,

So the time complexity of doing this is O(n).

Tags: Java less

Posted on Wed, 04 Dec 2019 11:45:12 -0500 by dzoddi