forked from carpeventus/coding-interviews
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLeastKNums.java
More file actions
128 lines (112 loc) · 3.61 KB
/
LeastKNums.java
File metadata and controls
128 lines (112 loc) · 3.61 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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package Chap5;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* 输入n个整数,找出其中最小的K个数。
* 例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
*/
public class LeastKNums {
/**
* 方法1:基于快排的切分
*/
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input == null || input.length == 0 || k > input.length || k <= 0) return list;
select(input, k - 1);
for (int i = 0; i < k; i++) {
list.add(input[i]);
}
return list;
}
/**
* 选择排名为k的元素,只是部分排序,时间复杂度为O(N)
*/
private int select(int[] array, int k) {
int low = 0;
int high = array.length - 1;
// high==low时只有一个元素,不切分
while (high > low) {
int j = partition(array, low, high);
if (j == k) return array[k];
else if (j > k) high = j - 1;
else if (j < k) low = j + 1;
}
return array[k];
}
/**
* 快速排序的切分方法
*/
private int partition(int[] array, int low, int high) {
int i = low;
int j = high + 1;
int v = array[low];
while (true) {
while (array[++i] < v) if (i == high) break;
while (array[--j] > v) if (j == low) break;
if (i >= j) break;
swap(array, i, j);
}
swap(array, low, j);
return j;
}
private void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
/**
* 方法2:基于最小堆
*/
public ArrayList<Integer> leastK(int[] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input == null || input.length == 0 || k > input.length || k == 0) return list;
int N = input.length;
// 堆的构造
for (int i = N / 2; i >= 1; i--) {
sink(input, i, N);
}
// 和堆顶交换k次
for (int i = 0; i < k; i++) {
// 存入堆顶的最小元素
list.add(input[0]);
swapForHeap(input, 1, N--);
sink(input, 1, N);
}
return list;
}
private void sink(int[] arr, int k, int N) {
while (2 * k <= N) {
int j = 2 * k;
// 左右子结点中选择小的
if (j < N && greater(arr, j, j + 1)) j++;
if (!greater(arr, k, j)) break;
swapForHeap(arr, k, j);
k = j;
}
}
private void swapForHeap(int[] array, int i, int j) {
int temp = array[i - 1];
array[i - 1] = array[j - 1];
array[j - 1] = temp;
}
private boolean greater(int[] arr, int i, int j) {
return arr[i - 1] > arr[j - 1];
}
/**
* 上面两个方法都改变了输入数组
* 直接使用Java内置的优先队列
*/
public ArrayList<Integer> getLeastK(int[] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input == null || input.length == 0 || k > input.length || k == 0) return list;
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
for (int a : input) {
maxHeap.offer(a);
// 只要size大于k,不断剔除最大值,最后优先队列里只剩最小的k个
if (maxHeap.size() > k) maxHeap.poll();
}
list.addAll(maxHeap);
return list;
}
}