题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
思路一:
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input.length <= 0 || k <= 0 || k > input.length) return list;
Arrays.sort(input);
for (int i = 0; i < k; i++)
list.add(input[i]);
return list;
}
}
思路二:
快排,时间复杂度为O(NlogN)~O(N^2),空间复杂度为O(logN)~O(N)
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input.length <= 0 || k <= 0 || k > input.length) return list;
QuickSort(input, 0, input.length - 1);
for (int i = 0; i < k; i++)
list.add(input[i]);
return list;
}
private void QuickSort(int[] arr, int low, int high)
{
int index;
while (low < high)
{
index = partition(arr, low, high);
QuickSort(arr, low, index - 1);
low = index + 1; //优化1:避免了尾递归
}
}
private int partition(int[] arr, int low, int high)
{
int flag = arr[low];
while(low < high)
{
while (low < high && arr[high] >= flag)
high--;
arr[low] = arr[high];
while(low < high && arr[low] <= flag)
low++;
arr[high] = arr[low];
}
arr[low] = flag;
return low;
}
}
快速选择:只作一次递归调用
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public static void main(String[] args) {
Solution s = new Solution();
int[] arr = {4,5,1,6,2,7,3,8,8,4,2};
List<Integer> list = new ArrayList<>();
list = s.GetLeastNumbers_Solution(arr, 5);
System.out.println(Arrays.toString(list.toArray())); //输出:[1, 2, 2, 3, 4]
}
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input.length <= 0 || k <= 0 || k > input.length) return list;
QuickSort(input, 0, input.length - 1, k);
for (int i = 0; i < k; i++)
list.add(input[i]);
return list;
}
private void QuickSort(int[] arr, int low, int high, int k)
{
if (low < high)
{
int m = (high + low) / 2;
if (arr[m] < arr[low]) swap(arr, low, m);
if (arr[high] < arr[low]) swap(arr, low, high);
if (arr[high] < arr[m]) swap(arr, m, high); //此时,m端的值为中间值
swap(arr, m, high - 1);
int flag = arr[high - 1];
int i = low;
int j = high - 1;
for ( ; ; )
{
while(arr[++i] < flag);
while (arr[--j] > flag);
if (i < j)
swap(arr, i, j);
else
break;
}
swap(arr, i, high - 1);
if (k <= i)
QuickSort(arr, low, i - 1, k);
else
QuickSort(arr, i + 1, high, k);
}
}
private void swap(int[] arr, int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
思路三:
堆排序
构建一个大顶堆的时间复杂度为O(N),重建大顶堆的时间复杂度为O(NlogN),总时间复杂度为O(NlogN)
空间复杂度O(1)
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input.length <= 0 || k <= 0 || k > input.length) return list;
HeapSort(input);
for (int i = 0; i < k; i++)
list.add(input[i]);
return list;
}
private void HeapSort(int[] arr) // 从小到大排序,建立一个大顶堆;从大到小排序,建立一个小顶堆
{
for (int i = arr.length/2-1; i >=0; i--) //非终端节点的范围0~length/2-1
{
HeapAdjust(arr, i, arr.length);
}
for (int i = arr.length - 1; i >= 0; i--)
{
swap(arr, 0, i);
HeapAdjust(arr, 0, i);
}
}
private void HeapAdjust (int[] arr, int s, int m)
{
int temp = arr[s];
int j = 2 * s + 1;
for (; j <= m - 1; j = 2 * j + 1)
{
if (j < m - 1 && arr[j] < arr[j + 1]) ++j;
if (temp >= arr[j]) break;
arr[s] = arr[j];
s = j;
}
arr[s] = temp;
}
private void swap(int[] arr, int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
思路四:
改进的堆排序
对数组的前k个数建立一个大顶堆,将剩余N-K个数,依次与堆顶比较,若比堆顶小,则替换堆顶,再调整堆。最终将堆里的k个数加入列表中。
建立一个大顶堆的时间复杂度为O(k),调整大顶堆的时间复杂度为O((N-k)logk),总的时间复杂度为O(Nlogk)
空间复杂度为O(k+1)即O(k)
最后输出的k个数可以不按照从小到大输出
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input.length <= 0 || k <= 0 || k > input.length) return list;
HeapSort(input, k);
for (int i = 0; i < k; i++)
list.add(input[i]);
return list;
}
private void HeapSort(int[] arr, int k) // 从小到大排序,建立一个大顶堆;从大到小排序,建立一个小顶堆
{
int[] karr = new int[k];
for (int i = 0; i < k; i ++)
karr[i] = arr[i];
for (int i = k/2-1; i >=0; i--) //非终端节点的范围0~length/2-1
{
HeapAdjust(karr, i, k);// // karr为大顶堆
}
for (int i = k; i < arr.length; i++)
{
if (arr[i] < karr[0])
{
karr[0] = arr[i];
HeapAdjust(karr, 0, k);
}
}
for (int i = 0; i < k; i++)
arr[i] = karr[i];
}
private void HeapAdjust (int[] arr, int s, int m)
{
int temp = arr[s];
int j = 2 * s + 1;
for (; j <= m - 1; j = 2 * j + 1)
{
if (j < m - 1 && arr[j] < arr[j + 1]) ++j;
if (temp >= arr[j]) break;
arr[s] = arr[j];
s = j;
}
arr[s] = temp;
}
}
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if (input.length <= 0 || k <= 0 || k > input.length) return list;
HeapSort(input, k);
for (int i = 0; i < k; i++)
list.add(input[i]);
return list;
}
private void HeapSort(int[] arr, int k) // 从小到大排序,先建立一个大顶堆;从大到小排序,先建立一个小顶堆
{
int[] karr = new int[k];
for (int i = 0; i < k; i ++)
karr[i] = arr[i];
for (int i = k/2-1; i >=0; i--) //非终端节点的范围0~length/2-1
{
HeapAdjust(karr, i, k);
}
for (int i = k; i < arr.length; i++)
{
if (arr[i] < karr[0])
{
karr[0] = arr[i];
HeapAdjust(karr, 0, k);
}
}
for (int i = k - 1; i >= 0; i--)//加循环
{
swap(karr, 0, i);
HeapAdjust(karr, 0, i);
}
for (int i = 0; i < k; i++)
arr[i] = karr[i];
}
private void HeapAdjust (int[] arr, int s, int m)
{
int temp = arr[s];
int j = 2 * s + 1;
for (; j <= m - 1; j = 2 * j + 1)
{
if (j < m - 1 && arr[j] < arr[j + 1]) ++j;
if (temp >= arr[j]) break;
arr[s] = arr[j];
s = j;
}
arr[s] = temp;
}
private void swap(int[] arr, int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}