LeetCode_Sorting_面试题 17.14. Smallest K LCCI 最小K个数【快速排序,partation优化】【java】【中等】

目录

一,题目描述

英文描述

中文描述

示例与说明

二,解题思路

三,AC代码

Java

四,解题过程

第一博

第二搏


一,题目描述

英文描述

Design an algorithm to find the smallest K numbers in an array.

中文描述

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例与说明

来源:力扣(LeetCode)
链接:力扣
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二,解题思路

借助快速排序的partation方法,这样就成了寻找partation后返回值为k的过程。

然后就可以按照二分法的技巧,改变待排序区间范围了。

三,AC代码

Java

class Solution {
    public void swap (int[] arr, int a, int b) {
        int tem = arr[a];
        arr[a] = arr[b];
        arr[b] = tem;
    }
    public int partion (int[] arr, int left, int right) {
        int index = (int) Math.random() * (right - left) + left;
        int pivot = arr[index];
        swap(arr, left, index);    // 将哨兵放在排序区间的左边界
        index = left;              // index指向排好序的数组的右边界
        // 将所有小于pivot的元素放到数组的前面,类似于插入排序
        for (int i = left + 1; i <= right; i++) {
            if (arr[i] < pivot) {
                index++;
                swap(arr, index, i);
            }
        }
        swap(arr, left, index);    // 将哨兵换回到合适的位置
        return index;
    }
    public void quickSort(int[] arr, int left, int right, int k) {
        if (k < left || k > right) return;
        int index = partion(arr, left, right);
        if (index < k - 1) {
            quickSort(arr, index + 1, right, k);
        } else if (index > k - 1) {
            quickSort(arr, left, index - 1, k);
        } else {
            return;
        }
    }
    public int[] smallestK(int[] arr, int k) {
        int[] ans = new int[k];
        if (k == 0 || arr == null) return ans;
        quickSort(arr, 0, arr.length - 1, k);
        // System.arraycopy(arr, 0, ans, 0, k);
        for (int i = 0; i < k; i++) {
            ans[i] = arr[i];
        }
        return ans;
    }
}

四,解题过程

第一博

我一眼就看出这一题需要用快速排序(不要求前k个数据的顺序)。快排可以很好的解决这个问题,只不过选择k这个过程可能比较魔幻(如果第一次随机就找到了第k小的数,那么当场算法结束,反之如果运气不太好,那就emmm)

有点类似于二分法的感觉。

class Solution {
    public void swap (int[] arr, int a, int b) {
        int tem = arr[a];
        arr[a] = arr[b];
        arr[b] = tem;
    }
    public int partion (int[] arr, int left, int right) {
        int index = (int) Math.random() * (right - left) + left;
        int pivot = arr[index];
        swap(arr, left++, index);
        index = left - 1;
        while (left < right) {
            while (left < right && arr[left] < pivot) left++;
            while (left < right && arr[right] > pivot) right--;
            if (left < right) swap(arr, left, right);
        }
        if (arr[left] > pivot) left--;
        swap(arr, left, index);
        return left;
    }
    public void quickSort(int[] arr, int left, int right, int k) {
        if (k < left || k > right) return;
        int index = partion(arr, left, right);
        if (index < k - 1) {
            quickSort(arr, index + 1, right, k);
        } else if (index > k - 1) {
            quickSort(arr, left, index - 1, k);
        } else {
            return;
        }
    }
    public int[] smallestK(int[] arr, int k) {
        int[] ans = new int[k];
        if (k == 0 || arr == null) return ans;
        quickSort(arr, 0, arr.length - 1, k);
        for (int i = 0; i < k; i++) {
            ans[i] = arr[i];
        }
        return ans;
    }
}

第二搏

超时?为啥会超时???

经过和大佬的代码仔细对比后,终于发现了问题。。。

真相只有一个:partation算法的实现

之前partation算法的实现(分别从左/右边界开始,定位大于/小于pivot的元素位置,然后交换位置)

优化后的partation算法实现(顺序遍历排序区间的元素,类似于插入排序的方法,维护一个已排序区间,将小于pivot的元素插入到这个区间中)

简单分析一下:

  • 从整体上来看,两种解法都是遍历一次数组,将元素进行划分。
  • 从细节上来看,优化后的方法内部只有一个简单的if分支判断,而之前的方法中额外包含了两个while循环(虽然看上去可以快速定位需要交换的元素,一次将两个元素放到正确的位置,但实际上还是对数组进行了一次遍历)

将这两个while放到大数据的范围上来看,它的开销确实不容小觑。。。

猜你喜欢

转载自blog.csdn.net/qq_41528502/article/details/121553309