描述
给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
数据范围:0\le k,n \le 100000≤k,n≤10000,数组中每个数的大小0 \le val \le 10000≤val≤1000
要求:空间复杂度 O(n)O(n) ,时间复杂度 O(nlogn)O(nlogn)
示例1
输入:
[4,5,1,6,2,7,3,8],4
复制返回值:
[1,2,3,4]
复制说明:
返回最小的4个数即可,返回[1,3,2,4]也可以
解决问题思路:时间复杂度 O(nlogn),空间复杂度o(n),典型得分治算法求解问题(附:其实堆排序也可以,堆排序空间复杂度只有O(1),性能更佳),本提附上分治法求解得代码
import java.util.ArrayList; public class Solution { public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { Merge_sort(input,0,input.length-1); ArrayList<Integer> list=new ArrayList(); int index=1; while(index<=k){ list.add(input[index++-1]); } return list; } public void Merge_sort(int[] A,int p,int r){//p为起始位置,r为结束位置 int q = (p+r)/2;//q为二分位置 if(p < r){ //递归调用 Merge_sort(A,p,q);//递归解决前半部分 Merge_sort(A,q + 1,r);//递归解决后半部分 //归并排序数据元素 Merge(A,p,q,r);//最后将所有有序数组完成归并 } } public void Merge(int[] A,int p,int q,int r){ int[] tmp = new int[r-p+1];//声明一个临时数组,长度为要归并数组的长度 int i = p; //记住左边数组第一个元素的下标 int j = q+1; //记住右边数组第一个元素的下标 int k = 0; while(i <= q && j <= r){ //左边数组元素和右边数组元素比较,把小的元素赋给临时数组 if(A[i] <= A[j]){ tmp[k++] = A[i++]; } else{ tmp[k++] = A[j++]; } } //把左边剩余的数组元素赋给临时数组 while(i <= q){ tmp[k++] = A[i++]; } //把右边剩余的数组元素赋给临时数组 while(j <= r){ tmp[k++] = A[j++]; } //用临时数组元素覆盖原数组元素 for(int k2 = 0;k2 < tmp.length;k2++){ A[k2+p] = tmp[k2]; } } }