题目描述
// 力扣
// 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、
// 2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
// 牛客
// 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字
// ,则最小的4个数字是1,2,3,4。
题解
// 暴力法 //
// 力扣
// 暴力法,能通过但没有意义
// 执行用时:8 ms, 在所有 Java 提交中击败了64.97%的用户
// 内存消耗:40 MB, 在所有 Java 提交中击败了17.80%的用户
import java.util.Arrays;
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
int[] res = new int[k];
Arrays.sort(arr);
for (int i = 0; i < k; i++) {
res[i] = arr[i];
}
return res;
}
}
如果用数组表示堆的话,根据层序顺序标号规则,将层序标号对应到数组索引中,那么在数组索引中找二叉树左右结点可以通过如下规律:找结点的左节点:索引2,找结点的右结点:索引2+1,找结点的父结点:索引 / 2(整数除法,要去除小数点)。
/// 最大堆法 ///
// 比较好的方法
// 牛客
// 运行时间:15ms
// 占用内存:9944k
import java.util.ArrayList;
import java.util.PriorityQueue; // 利用优先队列构建堆
import java.util.Comparator; // 比较器
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
if (k > input.length || k < 0) // 如果k值有问题,返回空数组
return new ArrayList<>();
// 优先队列默认是最小堆(最小值置顶),将其修改成最大堆(最大值置顶)
// 得到构建好的最大堆maxHeap
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
// for循环遍历input中的元素,将其放入num中
for (int num: input) {
maxHeap.add(num);
// 由于是最大堆,所以最大值一定会被置顶
// 当堆中元素超过k(达到k+1)了,那么置顶元素一定比其余k个数大,
// 将其弹出。input所有元素被遍历过,且在堆中被比较过大小,
// 所以能在堆中留下的k个数就是input里最小的k个数。
if (maxHeap.size() > k)
maxHeap.poll();
}
// 将堆以ArrayList格式返回
return new ArrayList<>(maxHeap);
}
}
// 力扣
// 执行用时:25 ms, 在所有 Java 提交中击败了13.48%的用户
// 内存消耗:39.6 MB, 在所有 Java 提交中击败了77.55%的用户
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Comparator;
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if (k > arr.length || k <= 0)
return new int[0];
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
for (int num: arr) {
maxHeap.add(num);
if (maxHeap.size() > k)
maxHeap.poll();
}
int[] res = new int[k];
ArrayList<Integer> kmin = new ArrayList<>(maxHeap);
toResList(kmin, res, k);
return res;
}
public void toResList(ArrayList<Integer> kmin, int[] res, int k) {
for (int i = 0; i < kmin.size(); i++) {
res[i] = kmin.get(i);
}
}
}
// 力扣
// 执行用时:27 ms, 在所有 Java 提交中击败了11.67%的用户
// 内存消耗:40.1 MB, 在所有 Java 提交中击败了8.06%的用户
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Comparator;
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if (k > arr.length || k <= 0)
return new int[0];
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
for (int num: arr) {
maxHeap.add(num);
if (maxHeap.size() > k)
maxHeap.poll();
}
int[] res = new int[k];
toResList(maxHeap, res);
return res;
}
public void toResList(PriorityQueue<Integer> maxHeap, int[] res) {
int i = 0;
for (int num : maxHeap) {
res[i++] = num;
}
}
}
/ 快速选择法 /
// 快速选择和快排很类似
// 牛客
// 运行时间:14ms
// 占用内存:9924k
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> res = new ArrayList<>();
if (k > input.length || k <= 0)
return res;
findKthSmallest(input, k); // 快选主函数
// 此时input前k个元素即为最小的k个元素
for (int i = 0; i < k; i++)
res.add(input[i]); // 将前k个元素存入res中
return res;
}
// 快速选择函数
// 找k个最小值
public void findKthSmallest(int[] input, int k) {
int low = 0, high = input.length - 1; // 初始化左右边界
while (low < high) {
int size = partition(input, low, high);
if (size == k) // 直到size等于k,停止循环
break;
if (size > k) // 最小的k个数一定在前size个数中
high = size - 1; // 右边界high左移
else // size < k // 在右侧数组中继续找最小的k个数
low = size + 1; // 左边界low右移
}
}
// 切分函数,我们希望使数组切分值的左边都是小元素,右边都是大元素
private int partition(int[] input, int low, int high) {
int split = input[low]; // 切分值初始化
int i = low, j = high + 1; // 双指针i,j遍历input元素
while (true) {
// i从左往右移,遍历到不小于split的元素为止
while (i != high && input[++i] < split);
// j从右往左移,遍历到不大于split的元素位置
while (j != low && input[--j] > split);
if (i >= j)
break;
// input[i]比split大,input[j]比split小,交换位置
swap(input, i, j);
}
swap(input, low, j); // input[j]比split值本身要小,交换位置
return j; // 返回
}
// 交换函数
private void swap(int[] input, int i, int j) {
int t = input[i];
input[i] = input[j];
input[j] = t;
}
}
// 力扣
// 执行用时:3 ms, 在所有 Java 提交中击败了83.07%的用户
// 内存消耗:39.8 MB, 在所有 Java 提交中击败了51.36%的用户
import java.util.ArrayList;
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if (k > arr.length || k <= 0)
return new int[0];
findKSmallest(arr, k);
int[] res = new int[k];
for (int i = 0; i < k; i++) {
res[i] = arr[i];
}
return res;
}
public void findKSmallest(int[] arr, int k) {
int low = 0, high = arr.length - 1;
while (true) {
int size = partition(arr, low, high);
if (size == k)
break;
if (size > k)
high = size - 1;
else
low = size + 1;
}
}
private int partition (int[] arr, int low, int high) {
int split = arr[low];
int i = low, j = high + 1;
while (true) {
while (i < high && arr[++i] < split);
while (j > low && arr[--j] > split);
if (i >= j)
break;
swap(arr, i, j);
}
swap(arr, low, j);
return j;
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}