Kotlin на LeetCode: ваш ключ к успешному собеседованию
Если вы пишете на Kotlin и готовитесь к техническому собеседованию, то рано или поздно окажетесь на LeetCode. Этот ресурс стал золотым стандартом для проверки алгоритмического мышления. Но есть один нюанс: большинство решений на форумах написаны на Python или Java. А Kotlin — язык гибкий и современный, и использовать его «в лоб» как Java — значит упустить половину возможностей.
В этой статье мы разберём, как эффективно решать задачи на LeetCode именно на Kotlin. Вы узнаете, какие функции языка помогут писать лаконичный и быстрый код, какие темы стоит изучить в первую очередь, и получите реальные примеры с пояснениями. Поехали!
Почему Kotlin — отличный выбор для LeetCode
Kotlin сочетает в себе лучшее из двух миров: объектно-ориентированное программирование (как в Java) и функциональные возможности (как в Scala или Python). Благодаря этому вы можете писать решения, которые одновременно читаются как псевдокод и работают быстро.
Вот три кита, на которых держится успех Kotlin на LeetCode:
- Лаконичность. Кода меньше — ошибок меньше. Kotlin избавляет от boilerplate (геттеры, сеттеры, точки с запятой).
- Безопасность null. NullPointerException — частая причина падений. В Kotlin система типов жёстко контролирует null, что особенно важно в сложных алгоритмах.
- Функции высшего порядка.
map,filter,foldи другие позволяют писать декларативные решения за пару строк.
Но есть и подводные камни. Например, рекурсия на Kotlin может быть не такой эффективной, как на Java, если не использовать хвостовую рекурсию (tailrec). Или работа с изменяемыми списками — иногда проще использовать MutableList, чем создавать новые копии.
Что нужно изучить перед тем, как начать решать задачи
Прежде чем нырять в пул задач, убедитесь, что вы уверенно владеете основами языка. Вот список тем, которые пригодятся на 90% задач:
1. Коллекции и их методы
LeetCode обожает задачи на массивы, списки и хеш-таблицы. В Kotlin стандартная библиотека коллекций очень богата. Запомните:
listOf(),mutableListOf()— создание списков.mapOf(),hashMapOf()— для словарей.groupBy,associateBy— для группировки данных.sortedBy,sortedWith— для сортировки по ключу.
2. Работа со строками
Строки в Kotlin неизменяемы, но есть удобные методы: toCharArray(), split(), substring(). Особенно полезен StringBuilder для конкатенации в циклах.
3. Базовые алгоритмические конструкции
Без них никуда: бинарный поиск, два указателя, скользящее окно, BFS/DFS для графов. Kotlin не добавляет магии, но позволяет писать эти алгоритмы чище.
4. Функциональное программирование
Используйте let, apply, also для цепочек вызовов. Но не переусердствуйте: на собеседовании важнее читаемость, чем количество строк.
Разбор реальных задач с примерами кода
Теперь перейдём к практике. Разберём три типовые задачи разного уровня сложности и покажем, как элегантно их решить на Kotlin.
Задача 1: Two Sum (Лёгкая)
Условие: Дан массив чисел и целевая сумма. Найти индексы двух чисел, которые в сумме дают target.
Решение на Kotlin:
fun twoSum(nums: IntArray, target: Int): IntArray {
val map = mutableMapOf<Int, Int>()
for ((index, value) in nums.withIndex()) {
val complement = target - value
if (map.containsKey(complement)) {
return intArrayOf(map[complement]!!, index)
}
map[value] = index
}
throw IllegalArgumentException("No solution")
}
Разбор: Используем хеш-таблицу для хранения значений и их индексов. withIndex() — идиоматичный способ получить индекс и элемент одновременно. Обратите внимание на !! — мы уверены, что ключ существует, так как проверили это в условии.
Задача 2: Valid Parentheses (Средняя)
Условие: Проверить, правильно ли расставлены скобки в строке: (), {}, [].
Решение на Kotlin:
fun isValid(s: String): Boolean {
val stack = ArrayDeque<Char>()
val map = mapOf(')' to '(', '}' to '{', ']' to '[')
for (char in s) {
if (char in map.values) {
stack.addLast(char)
} else if (stack.isNotEmpty() && stack.last() == map[char]) {
stack.removeLast()
} else {
return false
}
}
return stack.isEmpty()
}
Разбор: Здесь мы используем ArrayDeque — эффективную двустороннюю очередь. В Kotlin нет встроенного класса Stack (он устарел), но ArrayDeque отлично справляется. Обратите внимание на map.values — мы проверяем, является ли символ открывающей скобкой.
Задача 3: Binary Tree Inorder Traversal (Средняя)
Условие: Выполнить inorder обход бинарного дерева (левый узел → корень → правый узел) и вернуть список значений.
Решение на Kotlin (рекурсивное):
fun inorderTraversal(root: TreeNode?): List<Int> {
val result = mutableListOf<Int>()
fun dfs(node: TreeNode?) {
if (node == null) return
dfs(node.left)
result.add(node.`val`)
dfs(node.right)
}
dfs(root)
return result
}
Разбор: Используем локальную рекурсивную функцию dfs — это чище, чем отдельный метод. Обратите внимание на обратные кавычки вокруг val — это ключевое слово Kotlin, поэтому его нужно экранировать. Если дерево большое, лучше использовать итеративный подход со стеком, чтобы избежать переполнения стека вызовов.
Стратегия подготовки: как не утонуть в задачах
LeetCode — это марафон, а не спринт. Вот план, который поможет вам системно подготовиться:
- Начните с лёгких задач. Решите