面试题40. 最小的k个数
注意leetcode和牛客网的区别!!!! 返回值的类型不一致;
题目
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路1 — 直接调用排序算法!!!
Array.sort(int[] a);其实现也是快速排序~
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
// 注意 牛客网中该题是返回AyyayList类,leetcode中返回的是数组int[];
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if(k > input.length) {
return list; // 注意边界,此题k大于数组长度时,返回空的ArrayList<Integer>
}else{
Arrays.sort(input);// O(nlogn);
for(int i = 0; i < k; i++){
list.add(input[i]);
}
return list;
}
}
}
Array.sort()使用注意:
若是基本类型,需要转化为对应的对象类型(如:int转化为Integer)Arrays.sort()可以排序基本对象类型,但是不可以使用基本数据类型。
Arrays.sort()默认的是升序排序,降序排序可采用Collection.sort()匿名内部类。
数组与list一样,需要遍历出来
思路2 — 优化 快速排序~~
- 空间复杂度 O(1),不需要额外空间。
- 时间复杂度:和快速排序类似。由于快速选择只需要递归一边的数组,时间复杂度小于快速排序,期望时间复杂度为 O(n),最坏情况下的时间复杂度为 O(n^2)
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
// 注意 牛客网中该题是返回AyyayList类,leetcode中返回的是数组int[];
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> li = new ArrayList<Integer>();
//哭晕系列!!! 注意边界条件~~~~~
if(input.length == 0 || k > input.length || k == 0 || input == null ){
return li;
}else{
int[] sort = quickSelected(input, 0, input.length-1, k-1);
for(int i = 0; i < k; i++){
li.add(sort[i]);
}
return li;
}
}
public int[] quickSelected(int[] arr, int low, int high, int k){
int j = quickSort(arr, low, high);
// 只要切分位置刚好等于k,则切分位置左边的就是满足条件的最小的k个数
if(j == k){
return arr;
}
// 如果切分位置大于k值,代表需要减小左边的切分区间,继续从左边找最小的k个数。
if(j > k){
return quickSelected(arr, low, j-1, k);
}
// 如果切分位置小于k,说明右边还要继续从小到大的排序。
return quickSelected(arr, j+1, high, k);
}
// 快排切分, 每次切分都把比基数大的放在基数的右边,比基数小的放在技术左边。返回基数的切分位置。
public int quickSort(int[] arr, int low, int high){
int key = arr[low];
int i = low;
int j = high;
while(i < j){
while(key <= arr[j] && i < j){
j--;
}
while(key >= arr[i] && i < j){
i++;
}
if(i < j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
arr[low] = arr[j];
arr[j] = key;
return j;
}
}
思路3 —大根堆~~
注意: 需要掌握queue数据结构, 以及PriorityQueue优先队列(通过二叉小顶堆实现),优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C++的优先队列每次取最大元素)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Queue;
import java.util.PriorityQueue;
public class Solution {
// 注意 牛客网中该题是返回AyyayList类,leetcode中返回的是数组int[];
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> li = new ArrayList<Integer>();
if(input.length < k || k == 0){
return li;
}
Queue<Integer> heap = new PriorityQueue<>(k, (v1, v2) -> Integer.compare(v2, v1));
for(int num: input){
if(heap.isEmpty() || heap.size() < k || num < heap.peek()){
heap.offer(num);
}
if(heap.size() > k){
heap.poll();
}
}
for(int e: heap){
li.add(e);
}
return li;
}
}