select问题

  1. 1 问题描述
  2. 2 堆
  3. 3 划分
    1. 3.1 实现
    2. 3.2 复杂度分析

1 问题描述

给定一个集合$S$,$|S|$表示$S$元素的个数,找到$S$中第$k$大的元素,当$k=|S|/2$时,即中位数;

2 堆

维护一个k个元素的最小堆,BuildHeap复杂度为$O(k)$,然后遍历剩下$n-k$个元素,如果比堆顶元素大,则替换堆顶元素,执行percolate down操作,时间复杂度为$O((n - k)logk)$,总时间复杂度为$O(k + (n - k)logk)$,当$k=n/2$时,时间复杂度为$O(logn)$;

3 划分

取$s \in S$,将$S$按$s$划分为两部分$s_l$和$s_r$,其中$s_l$中的元素均小于等于$s$,$s_r$中的元素均大于$s$,
如果$|s_l| >= k$,则第$k$大数必定在$|s_l|$中;
如果$|s_l| == k - 1$,则$s$为第$k$大数;
如果$|s_l| < k - 1$,则第$k$大数必定在$s_r$中,且是$s_r$中第$k - |s_l| - 1$大元素;

3.1 实现

选取第一个元素为基准元素,为保证划分均匀(可以考虑所有元素相等的情况),i和j遇到和pivot相等的元素均停止遍历:

int partition(int a[], int left, int right)
{
    int i = left + 1, j = right;
    int pivot = a[left];

    while(i < j)
    {
        while(i <= j && a[i] < pivot) i++;
        while(i <= j && a[j] > pivot) j--;

        if(i < j)
        {
            swap(a[i], a[j]);
        }
        else
        {
            break;
        }
    }

    swap(a[left], a[j]);
    return j;
}

int findKth(int a[], int left, int right, int k)
{
    int p = partition(a, left, right);
    int left_len = p - left;
    if(left_len >= k)
    {
        return findKth(a, left, p - 1, k);
    }

    if(left_len == k - 1)
    {
        return a[p];
    }

    return findKth(a, p + 1, right, k - left_len - 1);
}

3.2 复杂度分析

1) 最坏情况
$T(n) = T(n - 1) + cn$
于是
$T(n) = T(n - 1) + cn$
$T(n - 1) = T(n - 2) + c(n - 1)$
...
$T(2) = T(1) + c1$

依次相加:
$T(n) = O(n)$

2) 平均情况
$T(n) = T(\frac{n}{2}) + cn$
于是
$\frac{T(n)}{n} = \frac{T(\frac{n}{2})}{n} + c$
$\frac{T(n)}{n} = \frac{1}{2}\frac{T(\frac{n}{2})}{\frac{n}{2}} + c$
令$A_n = \frac{T(n)}{n}$,则:
$A_n = \frac{1}{2}A_\frac{n}{2} + c$
故有
$A_n - 2C = \frac{1}{2}(A_\frac{n}{2} - 2c)$
令$B_n = A_n - 2C$,则:
$B_n = \frac{1}{2}B_\frac{n}{2}$
于是
$\frac{B_n}{B_\frac{n}{2}} = \frac{1}{2}$
$\frac{B_\frac{n}{2}}{B_\frac{n}{4}} = \frac{1}{2}$
...
$\frac{B_4}{B_2} = \frac{1}{2}$
$\frac{B_2}{B_1} = \frac{1}{2}$
依次相乘:
$\frac{B_n}{B_1} = {(\frac{1}{2})}^{\log(n)}$
$B_n = \frac{c}{n}$

$A_n = \frac{c}{n} + 2C$
$T_n = c + 2Cn = O(n)$


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至yj.mapple@gmail.com

文章标题:select问题

文章字数:576

本文作者:melonshell

发布时间:2020-01-20, 12:56:43

最后更新:2020-01-22, 11:21:55

原始链接:http://melonshell.github.io/2020/01/20/ds_select_Kth/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏

相册