-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathP0215_KthLargestElementInAnArray.java
More file actions
113 lines (101 loc) · 3.9 KB
/
P0215_KthLargestElementInAnArray.java
File metadata and controls
113 lines (101 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package yyl.leetcode.p02;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Random;
/**
* <h3>数组中的第K个最大元素</h3><br>
* 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。<br>
*
* <pre>
* 示例 1:
* 输入: [3,2,1,5,6,4] 和 k = 2
* 输出: 5
*
* 示例 2:
* 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
* 输出: 4
* </pre>
*
* 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。<br>
*/
public class P0215_KthLargestElementInAnArray {
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.findKthLargest(new int[] { 3, 2, 1, 5, 6, 4 }, 2));// 5
System.out.println(solution.findKthLargest(new int[] { 3, 2, 3, 1, 2, 4, 5, 5, 6 }, 4));// 4
System.out.println(solution.findKthLargest(new int[] { 1 }, 1));// 1
}
// 快速选择算法
// 目标:找到第n大的数
// 1、随机选择一个 pivot
// 2、根据这个pivot,将小于其的数放左边,大于其的数放右边
// 3、更新第n大数的估计值的位置,选择其中一边,直到=n
// 4、重复2、3步骤
// 时间复杂度:O(N),如果不使用随机数那么理论上复杂度是O(N)~O(N^2)
// 空间复杂度:O(1)
static class Solution {
private Random random = new Random();
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, k);
}
// 快速查找算法
private int quickSelect(int[] nums, int left, int right, int k) {
// 如果对于一个已排序的数组,我们每次都选择最大/最小的值为 pivot,那么时间复杂度为 O(N^2) 。
// 每次通过 random 选择 pivot 可以尽量避免最坏情况发生
int pivot = random.nextInt(right - left + 1) + left;
// 把 pivot 移动到最右的位置,以最右为标杆(nums[right])
swap(nums, right, pivot);
// 定义两个指针
int i = left;
int j = left;
while (j < right) {
// 如果 j 所在的指针是否小于等于 pivot的值,那么往左替换(和i位置交换)
if (nums[j] <= nums[right]) {
swap(nums, i, j);
i++;
}
j++;
}
// 把标杆替换到分割位置(此处j===right)
swap(nums, i, right);
// pivot 是我们要找的 Top k
if (right == k + i - 1) {
return nums[i];
}
// Top k 在右边
if (right > k + i - 1) {
return quickSelect(nums, i + 1, right, k);
}
// Top k 在左边
return quickSelect(nums, left, i - 1, k - (right - i + 1));
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
// 排序法
// 时间复杂度:O(NlogN)
// 空间复杂度:O(1)
static class Solution1 {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length - k];
}
}
// 使用最小堆
// 时间复杂度:O(NlogN)
// 空间复杂度:O(K)
static class Solution2 {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> queue = new PriorityQueue<>();
for (int num : nums) {
queue.add(num);
if (queue.size() > k)
queue.poll();
}
return queue.peek();
}
}
}