基于快速排序解决 leetcode hot215 查找数组中第k大的数字

题目描述

215. 数组中的第K个最大元素https://leetcode.cn/problems/kth-largest-element-in-an-array/

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

复制代码
输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

复制代码
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 10

快速排序背景

基本思想:分治法

排序过程:在数组中随机选取一个元素值作为中间值,然后对数组分区,使所有比中间值小的数据移动到数组左侧,使所有比中间值大的数据移动到数组右侧;

然后对左右两侧递归处理 使得子数组中只有一个数字为止。

快速排序代码

java 复制代码
public class Quick_Sort {


     /**
     * 快速排序思想
     * 1、随机选取数组中的一个数组作为中间值
     * 2、利用双指针  P1 P2 P1从-1下标位置,P2从0下标位置
     * 3、如果P2下标位置当前值小于 中间值 移动P1指针 交换P1 P2指针下的数组值
     * 4、P2扫描数组至最后一个位置 移动P1指针和P2指针下的值交换
     */
    public int[] sortArray(int[] nums) {
        //调用快速排序
        quicksort(nums, 0, nums.length - 1);
        return nums;
    }

       /**
     * 快速排序递归处理
     * 基本思想:分治法,连续处理数组将其连续缩小范围处理 直到子数组中只剩下一个值
     *
     * @param nums
     * @param start
     * @param end
     */
    public void quicksort(int[] nums, int start, int end) {
        if (end > start) {
            int pivot = partition(nums, start, end);
            quicksort(nums, start, pivot - 1);
            quicksort(nums, pivot + 1, end);
        }
    }

     /**
     * 分区函数
     *
     * @param nums
     * @param start:分区处理的第一个下标位置
     * @param end:分区处理数组的最后下标位置
     * @return:返回处理后的中间值的下标
     */
    public int partition(int[] nums, int start, int end) {
        // 获取下标随机值
        int random = new Random().nextInt(end - start + 1) + start;
        // 随机值
        int randomNum = nums[random];
        //将随机值和最后一个元素交换
        swap(nums, random, end);
        //创建双指针
        int P1 = start - 1;
        //遍历数组
        for (int P2 = start; P2 <= end; P2++) {
            //1、第一个逻辑 如果P2指针的元素值小于随机元素值 交换
            if (nums[P2] < randomNum) {
                P1++;
                //交换P2与P1的值
                swap(nums, P1, P2);
            }
        }
        P1++;
        swap(nums, P1, end);
        return P1;
    }

    private void swap(int[] nums, int i, int j) {
        if (i != j) {
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
    }


}

leetcode题目解题思路

因为题目中要找的是第k大的数字,那我们可以拿一个数组来模拟

复制代码
* [3,2,1,5,6,4], k = 2 
* [1,2,3,4,5,6] 寻找的目标值就是5 对应的数组下标为 nums.length - k = 6 - 2 = 4

如果使用快速排序的分区思路,只要不断缩小分区,之后寻找中间值的数组下标为4的数组值就可以:

解释一下:

因为分区之后 nums.length - k 数组左边部分 比这个之小 右边部分比这个值大 即使数组不是完全排序的,中间值也是第k大的数字

java 复制代码
class Solution {
    public int findKthLargest(int[] nums, int k) {
        int target = nums.length - k;
        int start = 0;
        int end = nums.length - 1;
        //分区查找中间值
        int index = partition(nums, start, end);
        while (index != target) {
            if (index > target) {
                //如果中间值下标大于目标值下标 则 目标值在左侧
                end = index - 1;
            } else {
                //如果中间值小标小于目标值下标 则 目标值在右侧
                start = index + 1;
            }
            //再次查找中间值
            index = partition(nums, start, end);
        }
        //返回目标值
        return nums[index];
    }

    /**
     * 分区函数
     *
     * @param nums
     * @param start:分区处理的第一个下标位置
     * @param end:分区处理数组的最后下标位置
     * @return:返回处理后的中间值的下标
     */
    public int partition(int[] nums, int start, int end) {
        // 获取下标随机值
        int random = new Random().nextInt(end - start + 1) + start;
        // 随机值
        int randomNum = nums[random];
        //将随机值和最后一个元素交换
        swap(nums, random, end);
        //创建双指针
        int P1 = start - 1;
        //遍历数组
        for (int P2 = start; P2 <= end; P2++) {
            //1、第一个逻辑 如果P2指针的元素值小于随机元素值 交换
            if (nums[P2] < randomNum) {
                P1++;
                //交换P2与P1的值
                swap(nums, P1, P2);
            }
        }
        P1++;
        swap(nums, P1, end);
        return P1;
    }
        private void swap(int[] nums, int i, int j) {
        if (i != j) {
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
    }
}
相关推荐
斯汤雷16 分钟前
Matlab绘图案例,设置图片大小,坐标轴比例为黄金比
数据库·人工智能·算法·matlab·信息可视化
云 无 心 以 出 岫1 小时前
贪心算法QwQ
数据结构·c++·算法·贪心算法
俏布斯1 小时前
算法日常记录
java·算法·leetcode
独好紫罗兰1 小时前
洛谷题单3-P5719 【深基4.例3】分类平均-python-流程图重构
开发语言·python·算法
SheepMeMe2 小时前
蓝桥杯2024省赛PythonB组——日期问题
python·算法·蓝桥杯
随便昵称2 小时前
蓝桥杯专项复习——前缀和和差分
c++·算法·前缀和·蓝桥杯
脑子慢且灵2 小时前
蓝桥杯冲刺:一维前缀和
算法·leetcode·职场和发展·蓝桥杯·动态规划·一维前缀和
姜威鱼2 小时前
蓝桥杯python编程每日刷题 day 21
数据结构·算法·蓝桥杯
CYRUS STUDIO2 小时前
Unidbg Trace 反 OLLVM 控制流平坦化(fla)
android·汇编·算法·网络安全·逆向·ollvm
ゞ 正在缓冲99%…2 小时前
leetcode22.括号生成
java·算法·leetcode·回溯