| 
 | 1 | +package com.leetcode.heaps;  | 
 | 2 | + | 
 | 3 | +import com.rampatra.base.MaxHeap;  | 
 | 4 | + | 
 | 5 | +import java.util.PriorityQueue;  | 
 | 6 | + | 
 | 7 | +import static org.junit.jupiter.api.Assertions.assertEquals;  | 
 | 8 | + | 
 | 9 | +/**  | 
 | 10 | + * Level: Medium  | 
 | 11 | + * Link: https://leetcode.com/problems/kth-largest-element-in-an-array/  | 
 | 12 | + * Description:  | 
 | 13 | + * Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not  | 
 | 14 | + * the kth distinct element.  | 
 | 15 | + * <p>  | 
 | 16 | + * Example 1:  | 
 | 17 | + * Input: [3,2,1,5,6,4] and k = 2  | 
 | 18 | + * Output: 5  | 
 | 19 | + * <p>  | 
 | 20 | + * Example 2:  | 
 | 21 | + * Input: [3,2,3,1,2,4,5,5,6] and k = 4  | 
 | 22 | + * Output: 4  | 
 | 23 | + * <p>  | 
 | 24 | + * Note:  | 
 | 25 | + * You may assume k is always valid, 1 ≤ k ≤ array's length.  | 
 | 26 | + *  | 
 | 27 | + * @author rampatra  | 
 | 28 | + * @since 2019-08-19  | 
 | 29 | + */  | 
 | 30 | +public class KthLargestElementInArray {  | 
 | 31 | + | 
 | 32 | +    /**  | 
 | 33 | +     * Runtime: <a href="https://leetcode.com/submissions/detail/252999497/">1 ms</a>.  | 
 | 34 | +     *  | 
 | 35 | +     * @param nums  | 
 | 36 | +     * @param k  | 
 | 37 | +     * @return  | 
 | 38 | +     */  | 
 | 39 | +    public static int findKthLargest(int[] nums, int k) {  | 
 | 40 | +        return heapSortUntilK(nums, k);  | 
 | 41 | +    }  | 
 | 42 | + | 
 | 43 | +    /**  | 
 | 44 | +     * In heapsort, after each iteration we have the max element at the end of the array. Ergo, if we run the algorithm  | 
 | 45 | +     * k times then we would have our kth largest element.  | 
 | 46 | +     *  | 
 | 47 | +     * @param a  | 
 | 48 | +     * @param k  | 
 | 49 | +     * @return  | 
 | 50 | +     */  | 
 | 51 | +    public static int heapSortUntilK(int[] a, int k) {  | 
 | 52 | +        buildMaxHeap(a);  | 
 | 53 | +        int count = 0;  | 
 | 54 | + | 
 | 55 | +        for (int i = a.length - 1; i > 0; i--) {  | 
 | 56 | +            if (count++ == k) {  | 
 | 57 | +                break;  | 
 | 58 | +            }  | 
 | 59 | +            swap(a, 0, i);  | 
 | 60 | +            maxHeapify(a, 0, i);  | 
 | 61 | +        }  | 
 | 62 | + | 
 | 63 | +        return a[a.length - k];  | 
 | 64 | +    }  | 
 | 65 | + | 
 | 66 | +    /**  | 
 | 67 | +     * Makes the array {@param a} satisfy the max heap property starting from  | 
 | 68 | +     * {@param index} till {@param end} position in array.  | 
 | 69 | +     * <p/>  | 
 | 70 | +     * See this {@link MaxHeap#maxHeapify} for a basic version of maxHeapify.  | 
 | 71 | +     * <p/>  | 
 | 72 | +     * Time complexity: O(log n).  | 
 | 73 | +     *  | 
 | 74 | +     * @param a  | 
 | 75 | +     * @param index  | 
 | 76 | +     * @param end  | 
 | 77 | +     */  | 
 | 78 | +    public static void maxHeapify(int[] a, int index, int end) {  | 
 | 79 | +        int largest = index;  | 
 | 80 | +        int leftIndex = 2 * index + 1;  | 
 | 81 | +        int rightIndex = 2 * index + 2;  | 
 | 82 | + | 
 | 83 | +        if (leftIndex < end && a[index] < a[leftIndex]) {  | 
 | 84 | +            largest = leftIndex;  | 
 | 85 | +        }  | 
 | 86 | +        if (rightIndex < end && a[largest] < a[rightIndex]) {  | 
 | 87 | +            largest = rightIndex;  | 
 | 88 | +        }  | 
 | 89 | + | 
 | 90 | +        if (largest != index) {  | 
 | 91 | +            swap(a, index, largest);  | 
 | 92 | +            maxHeapify(a, largest, end);  | 
 | 93 | +        }  | 
 | 94 | +    }  | 
 | 95 | + | 
 | 96 | +    /**  | 
 | 97 | +     * Converts array {@param a} in to a max heap.  | 
 | 98 | +     * <p/>  | 
 | 99 | +     * Time complexity: O(n) and is not O(n log n).  | 
 | 100 | +     */  | 
 | 101 | +    private static void buildMaxHeap(int[] a) {  | 
 | 102 | +        for (int i = a.length / 2 - 1; i >= 0; i--) {  | 
 | 103 | +            maxHeapify(a, i, a.length);  | 
 | 104 | +        }  | 
 | 105 | +    }  | 
 | 106 | + | 
 | 107 | + | 
 | 108 | +    /**  | 
 | 109 | +     * When you poll() on a PriorityQueue the smallest number in the queue is removed. Based on this property, we can  | 
 | 110 | +     * iterate over the entire array and in the end we would be left with the k largest element in the queue.  | 
 | 111 | +     *  | 
 | 112 | +     * @param nums  | 
 | 113 | +     * @param k  | 
 | 114 | +     * @return  | 
 | 115 | +     */  | 
 | 116 | +    public static int findKthLargestUsingPriorityQueue(int[] nums, int k) {  | 
 | 117 | +        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();  | 
 | 118 | + | 
 | 119 | +        for (int num : nums) {  | 
 | 120 | +            priorityQueue.add(num);  | 
 | 121 | + | 
 | 122 | +            if (priorityQueue.size() > k) {  | 
 | 123 | +                priorityQueue.poll();  | 
 | 124 | +            }  | 
 | 125 | +        }  | 
 | 126 | + | 
 | 127 | +        return priorityQueue.isEmpty() ? -1 : priorityQueue.peek();  | 
 | 128 | +    }  | 
 | 129 | + | 
 | 130 | +    private static void swap(int[] a, int firstIndex, int secondIndex) {  | 
 | 131 | +        a[firstIndex] = a[firstIndex] + a[secondIndex];  | 
 | 132 | +        a[secondIndex] = a[firstIndex] - a[secondIndex];  | 
 | 133 | +        a[firstIndex] = a[firstIndex] - a[secondIndex];  | 
 | 134 | +    }  | 
 | 135 | + | 
 | 136 | +    public static void main(String[] args) {  | 
 | 137 | +        assertEquals(5, findKthLargest(new int[]{3, 2, 1, 5, 6, 4}, 2));  | 
 | 138 | +        assertEquals(3, findKthLargest(new int[]{3, 2, 1, 5, 6, 4}, 4));  | 
 | 139 | + | 
 | 140 | +        assertEquals(5, findKthLargestUsingPriorityQueue(new int[]{3, 2, 1, 5, 6, 4}, 2));  | 
 | 141 | +        assertEquals(3, findKthLargestUsingPriorityQueue(new int[]{3, 2, 1, 5, 6, 4}, 4));  | 
 | 142 | +    }  | 
 | 143 | +}  | 
0 commit comments