每日刷题之(寻找第K大)快排

17 篇文章 0 订阅
1 篇文章 0 订阅

✅作者简介:我是18shou,一名即将秋招的java实习生

✨个人主页:_18shou

🔥系列专栏:牛客刷题专栏

📃推荐一款模拟面试、刷题神器👉 在线刷题面经模拟面试

🔥前言

	上篇文章也说过了我和牛客的渊源,从今天起打算开始用牛客每天刷题锻炼算法思维,每天博客打卡监督自己
    
    同时我也很很推荐大家来这儿坚持日常刷题,哪怕每天只刷一道题也会丰富自己的知识,让自己任何时候都不会出现不认识代码的情况。下面我分享一些我个人在牛客网刷到并解决的题,浅浅的解析,欢迎大家交流指正!

题目

寻找第K大

这题要用到快排的思想,不懂快排的小伙伴最好先去了解一下快排算法,程序员必备算法

首先我先发一下自己的快排模板

private static void quickSort(int[] arr, int l, int r) {
        // 子数组长度为 1 时终止递归
        if (l > r) return;
        // 哨兵划分操作(以 arr[l] 作为基准数)
        int i = l, j = r;
        while (i < j) {
            while (i < j && arr[j] >= arr[l]) j--;
            while (i < j && arr[i] <= arr[l]) i++;
            swap(arr, i, j);
        }
        swap(arr, i, l);
        // 递归左(右)子数组执行哨兵划分
        quickSort(arr, l, i - 1);
        quickSort(arr, i + 1, r);
    }
    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

思路

了解快排的大伙儿都知道,快排是以一个哨兵来划分,让左边的值全部大于哨兵,右边的值全部小于哨兵,然后对左右区间进行递归,最后达到有序的算法。

这题寻找第K大可以利用这种思想 ,当哨兵的索引值刚好等于k的时候,也就是哨兵左边刚好有k-1个数大于哨兵 (为什么是k- 1,因为索引是从0开始的)。如果它左边的元素比k−1多,说明第k大在其左边,直接二分法进入左边,不用管标杆元素右边:

这样就可以得出步骤

step 1:进行一次快排,大元素在左,小元素在右,得到的中轴p点。
step 2:如果 p - low + 1 = k,那么p点就是第K大。
step 3:如果 p - low + 1 > k,则第k大的元素在左半段,更新high = p - 1,执行step 1。
step 4:如果 p - low + 1 < k,则第k大的元素在右半段,更新low = p + 1, 且 k = k - (p - low + 1),排除掉前面部分更大的元素,再执行step1.(对右边区间进行递归的时候,因为只会递归右边,左边的值相当于被忽略了,所以k需要排除掉前面部分更大的元素)有序后 第1大是左边第一个数

代码

import java.util.*;

public class Solution {
    public int findKth(int[] a, int n, int K) {
        // write code here
        return quickSort(a, 0, n - 1, K);
    }
    public int quickSort(int a[], int low, int high, int k) {
        int p = findMid(a, low, high);
        if ( p - low + 1 == k) {
            return a[p];
        } else if ( p - low + 1 > k) {
            return quickSort(a, low, p - 1, k);
        } else {
            return quickSort(a, p + 1, high, k - (p - low + 1));
        }
    }
    public int findMid(int[]a, int low, int high) {
        if (low > high) {
            return 0 ;
        }
        int i = low;
        int j = high;
        int tmp = a[low];
        while (i < j) {
            while (i < j && a[j] <= tmp) {
                j--;
            }
            while (i < j && a[i] >= tmp) {
                i++;
            }
            swap(a, i, j);
        }
        swap(a, i, low);
        return i;
    }
    public void swap(int[]a, int low, int high) {
        int tmp = a[low];
        a[low] = a[high];
        a[high] = tmp;
    }
}

复杂度

时间复杂度:O(n),利用二分法缩短了时间——T(2/N)+T(N/4)+T(N/8)+……=T(N)
空间复杂度:O(n),递归栈最大深度
在这里插入图片描述

📃结语

兄弟们,一起来刷题👉嘎嘎的写题

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值