剑指offer-面试题30-最小的K个数

来源:互联网 发布:ivc电子目录软件 编辑:程序博客网 时间:2024/06/04 20:12

1,O(n)的算法,只有当我们可以修改输入的数组时可用

package case30_GetLeastNum;/** * 题目:输入n个整数,找出其中最小的k个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4 * 方法:利用partition函数完成,采用这种思路是有限制的。我们需要修改输入的数组,因为函数Partition会调整数组中数字的顺序 *  *  * @author WangSai * */public class GetLeastNum1 {/** *  * @param arr[] *            需要被寻找的数组 * @return 寻找出来满足条件的k个数字 */public static void main(String[] args) {int[] arr = { 4, 5, 1, 4, 4, 7, 3, 8 };int k = 4;getNumbers(arr, k);}// 通过partition函数,获取arrOut数组private static void getNumbers(int[] arr, int k) {// 异常值判断if (arr == null || arr.length < k || arr.length <= 0 || k <= 0)throw new IllegalArgumentException("输入的数组非法...");// 采用递归的方式完成int low = 0;int high = arr.length - 1;int index = partition(arr, low, high);while (index != k - 1) {if (index < k - 1) {low = index + 1;index = partition(arr, low, high);} else {high = index - 1;index = partition(arr, low, high);}}// 输出满足条件的数for (int i = 0; i < k; i++)System.out.print(arr[i] + " ");}// 快排中用到的partition函数private static int partition(int[] arr, int low, int high) {int pivotKey = arr[low];while (low < high) {while (low < high && arr[high] >= pivotKey)high--;arr[low] = arr[high];while (low < high && arr[low] <= pivotKey)low++;arr[high] = arr[low];}arr[low] = pivotKey;return low;}}


2,O(nlogk)的算法,特别适合处理海量数据

package case30_GetLeastNum;/** * 通过使用大顶堆完成。时间复杂度O(nlogk) *  * @author WangSai * */public class ByHeap1 {// 1,创建容器,并填充arr的前K个元素// 2,对这[0...K-1]序列创建大顶堆// 3,原序列从第K个开始,与[0...K-1]序列作比较,若大于堆顶元素则进行替换// 4,替换完成后,对序列重新调整变成大顶堆// 3,4步骤循环进行public static void main(String[] args) {int[] arr = { 1,2,3,4,5,6,7,8,4,433,32,0 };int k = 4;getLeatK(arr, k);int[] arr1={1};k =1;getLeatK(arr1, k);}// 获取最小的K个元素的方法private static void getLeatK(int[] arr, int k) {// 异常情况检测if (arr == null || arr.length <= 0 || arr.length < k || k <= 0)throw new IllegalArgumentException("输入的参数非法,请重新检查...");// 创建容器,并填充arr的前K个元素int[] heap = new int[k];for (int i = 0; i < k; i++) {heap[i] = arr[i];}buildMaxTopHeap(heap);// arr中的元素从第K个开始依次与大顶堆heap作比较,如果大于对顶则替换,并对新的堆做处理。for (int i = k; i < arr.length; i++) {if (arr[i] < heap[0]) {heap[0] = arr[i];adjustDownToUp(heap, 0);}}for (int i = 0; i < heap.length; i++) {System.out.print(heap[i] + "     ");}System.out.println();}// 将含有K个元素的无序序列构建大顶堆private static void buildMaxTopHeap(int[] heap) {for (int i = heap.length / 2 - 1; i >= 0; i--) {// 自底向上调整堆adjustDownToUp(heap, i);}}// 自底向上调整堆为大顶堆private static void adjustDownToUp(int[] heap, int i) {// 判断该节点与其子节点的大小int temp = heap[i];for (int j = 2 * i + 1; j < heap.length - 1; j = 2 *j + 1) { //i为初始化为节点k的左孩子,沿节点较大的子节点向下调整if (j <= heap.length - 1 && heap[j] < heap[j + 1]) //取节点较大的子节点的下标j++;//如果节点的右孩子>左孩子,则取右孩子节点的下标if (temp >= heap[j])//根节点 >=左右子女中关键字较大者,调整结束break;//根节点 <左右子女中关键字较大者else {heap[i] = heap[j];//将左右子结点中较大值array[i]调整到双亲节点上i = j;//【关键】修改k值,以便继续向下调整}}heap[i] = temp;//被调整的结点的值放入最终位置}}


3,O(n*k)的算法,用数组ArrayList保存K个数字,然后依次遍历数组arr中剩余的n-K个数字,依次比较并替换ArrayList中的最大值


package case30_GetLeastNum;import java.util.ArrayList;public class GetLeastNumByList {public static void main(String[] args) {//测试int[] arr = { 4, 5, 1, 4, 4, 7, 3, 8 };int k = 4;ArrayList<Integer> alist = getNum(arr, k);for (Integer num : alist)System.out.print(num + " ");}//获取满足条件的最小的k个数字private static ArrayList<Integer> getNum(int[] arr, int k) {// 判断异常情况if (arr == null || arr.length <= 0 || arr.length < k || k <= 0)throw new IllegalArgumentException("非法的输入参数...");// 新建容器,当容器中的数小于k的时候,直接添加。ArrayList<Integer> alist = new ArrayList<>();for (int i = 0; i < k; i++)alist.add(arr[i]);// 当容器满了之后,继续从剩下的arr[]数组的取出数。若取出来的数小于alist中最大的数,则直接替换掉。for (int j = k; j < arr.length; j++) {// 获取alist中最大的数值int indexOfMaxValue = getMaxIndex(alist);int max = alist.get(indexOfMaxValue);// 若arr中当前的值小于alist中的最大值,则替换掉alist中的最大值if (arr[j] < max) {alist.set(indexOfMaxValue, arr[j]);}}return alist;}// 获取arraylist中的最大数值的角坐标private static int getMaxIndex(ArrayList<Integer> alist) {int max = alist.get(0);int i = 0;for (int j = 1; j < alist.size(); j++) {if (alist.get(j) > max) {max = alist.get(j);i = j;}}return i;}}


1 0