Leetcode 1 最小的k个数

题目要求:输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

 

此问题简单思路是排序, 我们分别利用直接插入排序,归并,快排, 堆排序来实现!

 

直接插入排序, 时间复杂度O(n^2), 空间复杂度为O(1),  优化措施可以通过二分法来减少比较次数。

**
     * 直接插入法 容易把条件tempt<arr[j]变为条件arr[i]<arr[j]
     **/
    public void directInsertOrderSort(int[] arr) {
        int tempt = 0, j = 0;
        for (int i = 1; i < arr.length; i++) {
            tempt = arr[i];
// 可以优化利用二分法减少比较次数
for (j = i - 1; j >= 0 && tempt < arr[j]; j--) { arr[j + 1] = arr[j]; } arr[j + 1] = tempt;
} }

二分查找优化, 虽然减少比较次数,在数据比较少的情况下时间复杂度还是很高。

        // 之前 0, i-1都是有序元素
            int low = 0, high = i - 1;
            while (low <= high) { // 二分查找优化
                int mid = (low + high) / 2;
                if (arr[mid] >= tempt) high = mid - 1;
                else low = mid + 1;
            }
            for (j = i - 1; j >= high + 1; j++) {
                arr[j + 1] = arr[j];
            }
            arr[high + 1] = tempt;

快速排序------递归和非递归   平均时间复杂度O(nlogn), 如果数据基本有序,那么时间复杂度为O(n^2),空间复杂度最优是O(logn), 每次从中间分割. 最坏为O(n) 变成冒泡排序 

 /**
     * * 快速排序
     **/
    public void directQuickOrderSort(int[] arr, int low, int high) {
        /*if (low < high) {
            int mid = rQuickMindIndex(arr, low, high);
            directQuickOrderSort(arr, low, mid - 1);
            directQuickOrderSort(arr, mid + 1, high);
        }*/
        Stack<Integer> stack = new Stack<>();
        if (low < high) { // 非递归
            stack.push(high);
            stack.push(low);
            while (!stack.isEmpty()) {

                low = stack.pop();
                high = stack.pop();
                int mid = rQuickMindIndex(arr, low, high);
                if (mid - 1 > low) {
                    stack.push(mid - 1);
                    stack.push(low);
                }
                if (mid + 1 < high) {
                    stack.push(high);
                    stack.push(mid + 1);
                }
            }
        }
    }

    public int rQuickMindIndex(int arr[], int low, int high) {
        int tempt = arr[low]; // 保存当前需要替换的值
        while (low < high) { //
            while (high > low && arr[high] >= tempt) high--;
            arr[low] = arr[high];
            while (low < high && arr[low] < tempt) low++;
            arr[high] = arr[low];
        }

        arr[low] = tempt;
        return low;
    }

 

堆排序----> 此种方法是查找前k个数的最好方法, 空间复杂度为O(1), 首先维护一个k个元素的大顶堆,然后利用淘汰策略一个一个淘汰,组后输出这个堆。 

 /**
     * 堆排序  构建k个元素的大顶堆包括两步 堆调整,
     *
     */
    public void directHeapOrderSort(int[] arr, int k) {
        for (int i = k/ 2 - 1; i >= 0; i--) {
            // 调整数组中从i,.....len-1中数据使满足堆排序结构
            heapAdjust(arr, i, k);
        }
    }

    /**
     * 大顶堆的调整,
     * @param arr 数组
     * @param index 需要调整的元素索引位置
     * @param high 堆的元素个数
     */
    public void heapAdjust(int[] arr, int index, int high) {
        // 保存此位置上的数据信息
        int tempt = arr[index];
        for (int i = index * 2 + 1; i < high; i = i * 2 + 1) {
            if (i + 1 < high && arr[i + 1] > arr[i]) i++; //满足右边节点数据更小
            // 比较数据和index位置上数据的大小
            if (tempt < arr[i]) {
                arr[index] = arr[i];
                index = i;
            } else
                break;
        }
        arr[index] = tempt;
    }

 

 

归并排序  时间复杂度O(nlogn), 空间O(n), 需要一个辅助的拷贝数组空间。  

 public void directReclusiveOrderSort(int[] arr, int[] copy, int low, int high) {

        if (low >= high) return;
        int mid = (low + high) / 2;
        directReclusiveOrderSort(arr, copy, low, mid);
        directReclusiveOrderSort(arr, copy, mid + 1, high);
        directReclusiveAllToOneOrder(arr, copy, low, mid, high);

    }

    public void directReclusiveAllToOneOrder(int[] arr, int[] copy, int low, int mid, int high) {

        // 先每次新创建一个数组, 后期修改未全局创建一个数组
        //int[] copy=new int[1+high-low];

        int l1 = low, l2 = mid + 1, index = low;

        while (l1 <= mid && l2 <= high) {
            if (arr[l1] > arr[l2]) {
                copy[index++] = arr[l2++];
            } else {
                copy[index++] = arr[l1++];
            }
        }

        while (l1 <= mid) {
            copy[index++] = arr[l1++];
        }
        while (l2 <= high) {
            copy[index++] = arr[l2++];
        }

        for (int i = low; i <= high; i++) {
            arr[i] = copy[i];
        }
    }

 

posted @ 2020-03-21 10:56  张秀杰  阅读(162)  评论(0编辑  收藏  举报