侧边栏壁纸
博主头像
GabrielxD

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

  • 累计撰写 471 篇文章
  • 累计创建 108 个标签
  • 累计收到 9 条评论

目 录CONTENT

文章目录

【快速选择】第k个数

GabrielxD
2022-10-26 / 0 评论 / 0 点赞 / 22 阅读 / 683 字 / 正在检测是否收录...

题目

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;
}

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

0

评论区