E121. K-ая порядковая статистика за O (N)

e-maxx algorithm original: C/C++ #algorithm #array #emaxx #sequence #sort
题目文本会按所选界面语言从俄语翻译;代码保持不变。

Источник: e-maxx.ru/algo, страница PDF 399.

Пусть дан 数组 A длиной N и пусть given number K. 题目 заключается в том, чтобы find в этом 数组е K-ое по величине number, т.е. K-ую порядковую статистику.

Основная идея - использовать идеи 算法а быстрой сортировки. Собственно, 算法 несложный, сложнее доказать, что он работает в среднем за O (N), в отличие от быстрой сортировки.

实现 в виде нерекурсивной функции:

template <class T>

T order_statistics (std::vector<T> a, unsigned n, unsigned k)

{

using std::swap;

for (unsigned l=1, r=n; ; )

{

if (r <= l+1)

{

// текущая часть состоит из 1 или 2 elementов -

// легко можем find ответ

if (r == l+1 && a[r] < a[l])

swap (a[l], a[r]);

return a[k];

}

// упорядочиваем a[l], a[l+1], a[r]

unsigned mid = (l + r) >> 1;

swap (a[mid], a[l+1]);

if (a[l] > a[r])

swap (a[l], a[r]);

if (a[l+1] > a[r])

swap (a[l+1], a[r]);

if (a[l] > a[l+1])

swap (a[l], a[l+1]);

// выполняем разделение

// барьером является a[l+1], т.е. медиана среди a[l], a[l+1],

a[r]

unsigned

i = l+1,

j = r;

const T

cur = a[l+1];

for (;;)

{

while (a[++i] < cur) ;
while (a[--j] > cur) ;
if (i > j)

break;

swap (a[i], a[j]);

}

// вставляем барьер

a[l+1] = a[j];

a[j] = cur;

// продолжаем работать в той части,

// которая должна содержать искомый element

if (j >= k)

r = j-1;

if (j <= k)

l = i;

} }

Следует заметить, что в стандартной библиотеке C++ этот 算法 уже реализован - он называется nth_element.

C# 解法

自动草稿,提交前请检查
using System;
using System.Collections.Generic;
using System.Linq;

public static class AlgorithmDraft
{
    // Auto-generated C# draft from the original e-maxx C/C++ listing. Review before production use.
    template <class T>
    T order_statistics (std::vector<T> a, unsigned n, unsigned k)
    {
            using std::swap;
            for (unsigned l=1, r=n; ; )
            {
                    if (r <= l+1)
                    {
                            // текущая часть состоит из 1 или 2 элементов -
                            //       легко можем найти ответ
                            if (r == l+1 && a[r] < a[l])
                                    swap (a[l], a[r]);
                            return a[k];
                    }
                    // упорядочиваем a[l], a[l+1], a[r]
                    unsigned mid = (l + r) >> 1;
                    swap (a[mid], a[l+1]);
                    if (a[l] > a[r])
                            swap (a[l], a[r]);
                    if (a[l+1] > a[r])
                            swap (a[l+1], a[r]);
                    if (a[l] > a[l+1])
                            swap (a[l], a[l+1]);
                    // выполняем разделение
                    // барьером является a[l+1], т.е. медиана среди a[l], a[l+1],
    a[r]
                    unsigned
                            i = l+1,
                            j = r;
                    const T
                            cur = a[l+1];
                    for (;;)
                    {
                            while (a[++i] < cur) ;
                            while (a[--j] > cur) ;
                            if (i > j)
                                    break;
                            swap (a[i], a[j]);
                    }
                    // вставляем барьер
                    a[l+1] = a[j];
                    a[j] = cur;
                    // продолжаем работать в той части,
                    //       которая должна содержать искомый элемент
                    if (j >= k)
                            r = j-1;
                    if (j <= k)
                            l = i;
            }
    }
}

C++ 解法

匹配/原始
template <class T>
T order_statistics (std::vector<T> a, unsigned n, unsigned k)
{
        using std::swap;
        for (unsigned l=1, r=n; ; )
        {
                if (r <= l+1)
                {
                        // текущая часть состоит из 1 или 2 элементов -
                        //       легко можем найти ответ
                        if (r == l+1 && a[r] < a[l])
                                swap (a[l], a[r]);
                        return a[k];
                }
                // упорядочиваем a[l], a[l+1], a[r]
                unsigned mid = (l + r) >> 1;
                swap (a[mid], a[l+1]);
                if (a[l] > a[r])
                        swap (a[l], a[r]);
                if (a[l+1] > a[r])
                        swap (a[l+1], a[r]);
                if (a[l] > a[l+1])
                        swap (a[l], a[l+1]);
                // выполняем разделение
                // барьером является a[l+1], т.е. медиана среди a[l], a[l+1],
a[r]
                unsigned
                        i = l+1,
                        j = r;
                const T
                        cur = a[l+1];
                for (;;)
                {
                        while (a[++i] < cur) ;
                        while (a[--j] > cur) ;
                        if (i > j)
                                break;
                        swap (a[i], a[j]);
                }
                // вставляем барьер
                a[l+1] = a[j];
                a[j] = cur;
                // продолжаем работать в той части,
                //       которая должна содержать искомый элемент
                if (j >= k)
                        r = j-1;
                if (j <= k)
                        l = i;
        }
}

Java 解法

自动草稿,提交前请检查
import java.util.*;
import java.math.*;

public class AlgorithmDraft {
    // Auto-generated Java draft from the original e-maxx C/C++ listing. Review before production use.
    template <class T>
    T order_statistics (std::vector<T> a, unsigned n, unsigned k)
    {
            using std::swap;
            for (unsigned l=1, r=n; ; )
            {
                    if (r <= l+1)
                    {
                            // текущая часть состоит из 1 или 2 элементов -
                            //       легко можем найти ответ
                            if (r == l+1 && a[r] < a[l])
                                    swap (a[l], a[r]);
                            return a[k];
                    }
                    // упорядочиваем a[l], a[l+1], a[r]
                    unsigned mid = (l + r) >> 1;
                    swap (a[mid], a[l+1]);
                    if (a[l] > a[r])
                            swap (a[l], a[r]);
                    if (a[l+1] > a[r])
                            swap (a[l+1], a[r]);
                    if (a[l] > a[l+1])
                            swap (a[l], a[l+1]);
                    // выполняем разделение
                    // барьером является a[l+1], т.е. медиана среди a[l], a[l+1],
    a[r]
                    unsigned
                            i = l+1,
                            j = r;
                    const T
                            cur = a[l+1];
                    for (;;)
                    {
                            while (a[++i] < cur) ;
                            while (a[--j] > cur) ;
                            if (i > j)
                                    break;
                            swap (a[i], a[j]);
                    }
                    // вставляем барьер
                    a[l+1] = a[j];
                    a[j] = cur;
                    // продолжаем работать в той части,
                    //       которая должна содержать искомый элемент
                    if (j >= k)
                            r = j-1;
                    if (j <= k)
                            l = i;
            }
    }
}

Материал разбит как 算法ическая 题目: изучить постановку, понять асимптотику и реализовать 算法 на выбранном языке.

Vacancies for this task

活跃职位 with overlapping task tags are 已显示.

所有职位
目前还没有活跃职位。