Сортировка
H-индекс
Найти максимальное h, при котором есть h статей с не менее чем h цитированиями
Постановка задачи
Описание (LeetCode - 274. H-Index)
Дан массив citations, где citations[i] - количество цитирований i-й статьи
исследователя.
Нужно вернуть H-индекс исследователя.
H-индекс определяется как максимальное значение h, при котором данный
исследователь опубликовал не менее h статей, каждая из которых была
процитирована не менее h раз.
Пример 1:
citations = [3, 0, 6, 1, 5]
Результат:
3
Пояснение:
У исследователя есть 3 статьи с количеством цитирований 3, 5 и 6. Все
они процитированы не менее 3 раз. При этом H-индекс не может быть 4, потому
что нет 4 статей с как минимум 4 цитированиями.
Пример 2:
citations = [1, 3, 1]
Результат:
1
Ограничения:
n == citations.length1 <= n <= 50000 <= citations[i] <= 1000
Решение
В этой задаче сортировка помогает превратить определение H-индекса в простой
проход по массиву. Нам нужно найти максимальное число h, для которого
существует хотя бы h статей с количеством цитирований не меньше h.
Если отсортировать цитирования по возрастанию, то для каждого индекса i мы
можем заметить важный факт: справа от i, включая сам i, находится n - i
статей, и каждая из них имеет не менее citations[i] цитирований.
Идея решения:
Отсортируем citations по возрастанию. Затем пойдем слева направо. Для каждой
позиции i посчитаем:
h = n - i
Это количество статей, которые находятся справа от i и имеют цитирований не
меньше citations[i].
Если citations[i] >= h, значит, у нас есть как минимум h статей, каждая из
которых имеет не менее h цитирований. Поскольку мы идем слева направо, первое
такое h будет максимально возможным.
Почему первое найденное значение максимальное? В начале прохода h максимально
и равно n. Затем h уменьшается на 1 на каждом шаге. Как только условие
становится истинным, мы нашли самый большой H-индекс.
Основные шаги:
- Сортируем
citationsпо возрастанию. - Идем по индексам от
0доn - 1. - Для каждого индекса считаем
h = n - i. - Если
citations[i] >= h, возвращаемh. - Если такого индекса нет, возвращаем
0.
Рассмотрим пример:
citations = [3, 0, 6, 1, 5]
После сортировки:
citations = [0, 1, 3, 5, 6]
Проверяем позиции:
i = 0,h = 5,citations[i] = 0. Условие не выполняется.i = 1,h = 4,citations[i] = 1. Условие не выполняется.i = 2,h = 3,citations[i] = 3. Условие выполняется.
Ответ равен 3.
Эту задачу также можно решить через подсчет частот за O(n), так как
цитирования можно сгруппировать по значениям. Но решение через сортировку проще
объяснить, и оно наглядно показывает сам паттерн.
Оценка сложности
Временная сложность
Сортировка массива длины n занимает O(n log n). После этого мы выполняем
один проход за O(n).
Итоговая временная сложность: O(n log n).
Пространственная сложность
Если не учитывать память, необходимую для встроенной сортировки, мы храним
только несколько переменных. Пространственная сложность составляет O(1).
Код решения
Приведем код решения.
func hIndex(citations []int) int {
sort.Ints(citations)
n := len(citations)
for i := 0; i < n; i++ {
h := n - i
if citations[i] >= h {
return h
}
}
return 0
}Итоги
Задача H-Index - пример того, как сортировка помогает напрямую связать значение элемента с количеством элементов справа от него.
- Суть алгоритма: после сортировки по возрастанию для каждого индекса
iсправа находитсяn - iстатей. Еслиcitations[i] >= n - i, значит, эти статьи дают H-индексn - i. - Эффективность:
- Временная сложность:
O(n log n), потому что основное время занимает сортировка. - Пространственная сложность:
O(1), если не учитывать память встроенной сортировки.
- Временная сложность:
- Граничные случаи:
- Все цитирования равны
0: условие не выполнится ни разу, ответ0. - Одна статья: ответ
1, если у нее есть хотя бы одно цитирование, и0в противном случае. - Очень большие значения цитирований: H-индекс не может превышать общее количество статей.
- Все цитирования равны
- Сортировка дает простой и понятный способ проверить кандидатов на H-индекс. Первое подходящее значение при проходе слева направо будет максимально возможным.