З мого коментаря спочатку: Це тісно пов'язане з великою кількістю, всюдисущою в оцінці академічної продуктивності, індексом Гірша, більш відомим як -indexh . Коротше кажучи, вона визначається як кількість публікацій яка має таке, що кожне з них має принаймні h цитат (найбільший з таких h ).hhh
Єдиний спосіб, по якому ваша проблема відрізняється, це те, що вас зацікавило б не тільки те, скільки публікацій відповідає критерію, а й те, що їх кількість цитованих , але це тривіальна модифікація. Дані вже є, оригінальний алгоритм просто скидає їх.
Загально реалізований розрахунок досить простий і погоджується з відповіддю Кароліс Юоделі .
Оновлення: Залежно від розміру та характеру ваших даних, можливо, варто вивчити методи, які частково сортують масив, фільтруючи дані вище та нижче основної точки (на думку про швидкий вибір). Тоді залежно від того, чи є занадто мало або занадто багато, відрегулюйте поворот і повторіть підмножину, яка містить його тощо. Вам не потрібен порядок між елементами, вищими за , і, звичайно, не між тими, що нижче цього. Так, наприклад, щойно ви знайшли всі елементи більші або рівні h 1, і там менше h 1hh1h1 , вам більше не потрібно торкатися цього підмножини, просто додайте до нього. Це перетворює рекурсію, притаманну швидкості скорочення, до хвостової рекурсії і, таким чином, може бути переписана у цикл.
Мій Haskell трохи іржавий, але це має робити те, що я описав вище, і, здається, працює. Сподіваюся, це можна зрозуміти певною мірою, я радий надати подальше пояснення.
-- just a utility function
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : merge xs ys
-- the actual implementation
topImpl :: [Int] -> [Int] -> [Int]
topImpl [] granted = granted
topImpl (x:xs) granted
| x == (1 + lGreater + lGranted) = x : merge greater granted
| x > (1 + lGreater + lGranted) = topImpl smaller (x : merge greater granted)
| otherwise = topImpl greater granted
where smaller = [y | y <- xs, y < x]
greater = [y | y <- xs, y >= x]
lGreater = length greater
lGranted = length granted
-- starting point is: top of whole array, granted is empty
top :: [Int] -> [Int]
top arr = topImpl arr []
Ідея полягає в тому, щоб зібрати granted
те, що ви знаєте, обов'язково братиме участь у результаті, а не сортувати його далі. Якщо greater
разом з x
пристосуваннями нам пощастить, інакше нам потрібно спробувати з меншим набором. (Стрижкою x
- це просто те, що сталося, є першим пунктом підспілу, який зараз розглядається.) Зауважте, що суттєвою перевагою перед прийняттям найбільших елементів по черзі є те, що ми робимо це на блоках середнього розміру і не потрібно їх сортувати далі.remaining/2
Приклад:
Давайте візьмемо ваш набір [1,3,4,1,3,6]
.
x = 1
, granted = []
, greater = [3,4,1,3,6]
. О, ми потрапили в патологічний випадок, коли стрижень занадто малий (насправді такий малий, що smaller
порожній) прямо на першому кроці. На щастя, наш альго готовий до цього. Він відкидає x
і повторює спробу greater
поодинці.
x = 3
, granted = []
, greater = [4,3,6]
. Разом вони утворюють масив довжиною 4, але у нас є лише обмежений знизу на 3, тому це занадто багато. Повторіть greater
самостійно.
x = 4
, granted = []
, greater = [6]
. Це дає масив з 2 елементів ≥ 4 у кожному, мабуть, ми могли б використати ще деякі з них. Тримайте це і повторіть smaller = [3]
.
x = 3
, granted = [4,6]
, greater = []
. Це разом дає масив з 3 елементів ≥ 3 кожен, тож ми маємо наше рішення [3,4,6]
і ми можемо повернутися. (Зверніть увагу, що перестановка може змінюватись залежно від впорядкування введення, але завжди міститиме найвищі можливі умови, ніколи[3,3,6]
ні [3,3,4]
для вашого прикладу.)
(До уваги. Зауважимо, що рекурсія дійсно просто згорнулась до циклу.) Складність дещо краща, ніж швидкодію, через багато збережених порівнянь:
n - 1 порівняння
O ( журналn )O ( n ) порівняння в загальній складності
нO(n2)
У наведеному вище коді є декілька непотрібних порівнянь, як, наприклад, підрахунок, smaller
потрібен він нам чи ні, їх можна легко усунути. (Я думаю, що ледача оцінка допоможе про це.)