开头先来一个小插曲,关于「快排」相关总结可见 详解快排及其应用;关于「详解堆排序」相关总结可见 详解堆排序「优先队列」
这个题可以用两种方法:堆排序 && 快排
看到很多人说不能使用 Java 中的PriorityQueue,需要自己手动实现,所以这里使用自己实现的小根堆
时间复杂度:O(NlogK);空间复杂度:O(K)
xxxxxxxxxxclass Solution { public int findKthLargest(int[] nums, int k) { MyPQ pq = new MyPQ(k); for (int num : nums) { if (pq.size() < k) pq.offer(num); else if (pq.peek() < num) { pq.poll(); pq.offer(num); } } return pq.peek(); }}class MyPQ { private static final int CAPACITY = 11; private int[] pq; private int size; public MyPQ() { pq = new int[CAPACITY]; size = 0; } public MyPQ(int c) { pq = new int[c + 1]; size = 0; } public void offer(int x) { pq[++size] = x; up(size); } public int poll() { int x = pq[1]; swap(1, size--); down(1); return x; } public int peek() { return pq[1]; } public int size() { return size; } private void up(int k) { while (k > 1 && pq[k] < pq[k / 2]) { swap(k, k / 2); k >>= 1; } } private void down(int k) { while (2 * k <= size) { int j = 2 * k; if (j < size && pq[j] > pq[j + 1]) j++; if (pq[k] < pq[j]) break; swap(k, j); k = j; } } private void swap(int i, int j) { int t = pq[i]; pq[i] = pq[j]; pq[j] = t; }}时间复杂度:O(N);空间复杂度:O(1)
关于时间复杂度的分析,可见 时间复杂度分析
xxxxxxxxxxprivate int k;private Random r = new Random();public int findKthLargest(int[] nums, int k) { this.k = k; return sort(nums, 0, nums.length - 1);}private int sort(int[] nums, int lo, int hi) { int p = partition(nums, lo, hi); if (p > k - 1) return sort(nums, lo, p - 1); else if (p < k - 1) return sort(nums, p + 1, hi); return nums[p]; // ------ 补充一个迭代版本 ------ // while (lo <= hi) { // int p = partition(nums, lo, hi); // if (p > k - 1) hi = p - 1; // else if (p < k - 1) lo = p + 1; // else return nums[p]; // } // return 0; // ----------- end -----------}private int partition(int[] nums, int lo, int hi) { int p = r.nextInt(hi - lo + 1) + lo; swap(nums, lo, p); int pivot = nums[lo]; int i = lo + 1, j = hi; while (i <= j) { while (i < hi && nums[i] >= pivot) i++; while (j > lo && nums[j] < pivot) j--; if (i >= j) break; swap(nums, i, j); } swap(nums, lo, j); return j;}private void swap(int[] nums, int i, int j) { int t = nums[i]; nums[i] = nums[j]; nums[j] = t;}对于一组有序数据:
当
所以,该问题转化为:当
假设求第 2 大,此时数组为:[5, 5, 4, 4, 4, 3]
按照上述方法求,那么第 2 大的数为 5,但此时第二大的数应该为 4
这里使用「堆排序」的方法,用一个Set记录已经出现过的数字,如果再次出现,则跳过
具体代码如下:
public int findKthLargest(int[] nums, int k) { MyPQ pq = new MyPQ(k); Set<Integer> set = new HashSet<>(); for (int num : nums) { if (set.contains(num)) continue; else set.add(num); if (pq.size() < k) pq.offer(num); else if (pq.peek() < num) { pq.poll(); pq.offer(num); } } return pq.peek();}