侧边栏壁纸
博主头像
GabrielxD

列車は必ず次の駅へ。では舞台は?私たちは?

  • 累计撰写 674 篇文章
  • 累计创建 128 个标签
  • 累计收到 20 条评论

目 录CONTENT

文章目录

【快速选择】第k个数

GabrielxD
2022-10-26 / 0 评论 / 0 点赞 / 392 阅读 / 799 字
温馨提示:
本文最后更新于 2023-04-17,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

题目

786. 第k个数


给定一个长度为 nn 的整数数列,以及一个整数 kk,请用快速选择算法求出数列从小到大排序后的第 kk 个数。

输入格式

第一行包含两个整数 nnkk

第二行包含 nn 个整数(所有整数均在 11091 \sim 10^9 范围内),表示整数数列。

输出格式

输出一个整数,表示数列的第 kk 小数。

数据范围

1n1000001 \le n \le 100000,
1kn1 \le k \le n

输入样例:

5 3
2 4 1 5 3

输出样例:

3

解题

方法一:快速选择

思路

快速排序在完成前两步:

  1. 找到分界点 p(有三种选择:q[l]q[l + r >> 1]q[r])。
  2. 将区间 [l,r][l, r] 划分为两段,使得分界点左边所有数 LeftpLeft \le p,分界点右边所有数 RightqRight \ge q

之后,会得到一个具有二段性的序列:

image-20221026163820505

此时设序列分界点左边有 SLS_L 个元素,右边有 SRS_R 个元素,那么:

  • 如果 kSLk \le S_L ,递归 LeftLeft 找第 kk 小的数。
  • 如果 k>SLk > S_L ,递归 RightRight 找第 kSLk - S_L 小的数。

代码

import java.util.*;
import java.io.*;

public class Main {
    static int[] nums;
    
    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        in.nextToken();
        int n = (int) in.nval;
        in.nextToken();
        int k = (int) in.nval;
        nums = new int[n];
        for (int i = 0; i < n; ++i) {
            in.nextToken();
            nums[i] = (int) in.nval;
        }
        System.out.println(quickSort(0, n - 1, k));
    }
    
    static int quickSort(int l, int r, int k) {
        if (l == r) return nums[l];
        int p = nums[l + r >> 1], i = l - 1, j = r + 1;
        while (i < j) {
            do ++i; while (nums[i] < p);
            do --j; while (nums[j] > p);
            if (i < j) {
                int t = nums[i];
                nums[i] = nums[j];
                nums[j] = t;
            }
        }
        int sl = j - l + 1;
        if (k <= sl) return quickSort(l, j, k);
        return quickSort(j + 1, r, k - sl);
    }
}

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int n, k;
int q[N];

int quick_sort(int q[], int l, int r, int k) {
    if (l == r) return q[l];
    int p = q[l + r >> 1], i = l - 1, j = r + 1;
    while (i < j) {
        do ++i; while (q[i] < p);
        do --j; while (q[j] > p);
        if (i < j) swap(q[i], q[j]);
    }
    int sl = j - l + 1;
    if (k <= sl) return quick_sort(q, l, j, k);
    return quick_sort(q, j + 1, r, k - sl);
}

int main () {
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i) scanf("%d", &q[i]);
    printf("%d", quick_sort(q, 0, n - 1, k));
    
    return 0;
}
#include <iostream>

using namespace std;

const int N = 1e5 + 10;
int n, k, a[N];

int qsort(int l, int r) {
    if (l >= r) return a[l];
    int p = a[l + r >> 1], i = l - 1, j = r + 1;
    while (i < j) {
        while (a[++i] < p);
        while (a[--j] > p);
        if (i < j) swap(a[i], a[j]);
    }
    return k <= j ? qsort(l, j) : qsort(j + 1, r);
}

int main() {
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    --k;
    printf("%d\n", qsort(0, n - 1));

    return 0;
}

时间复杂度:O(n)O(n)

0

评论区