Собеседование на позицию Middle JavaScript разработчика: примеры задач и необходимые знания
Разбор нескольких задач, с которыми вы можете столкнуться при прохождении собеседования, а также общие советы для интервью.
37К открытий40К показов
Дмитрий Шостак
ведущий Frontend-разработчик IT-компании <a href="https://mediasoft.team/">MediaSoft</a>
Многие разработчики не любят, когда на собеседовании их просят писать код, но иногда это неизбежно. В этом материале я разберу несколько задач, с которыми вы можете столкнуться при прохождении интервью на позицию Middle JavaScript разработчика.
Какие знания понадобятся:
- JavaScript;
- базовые структуры данных;
- большое O.
Как подойти к решению задач:
- размышляйте вслух;
- не торопитесь и не сдавайтесь;
- работайте с энтузиазмом.
JavaScript
Не могу не подчеркнуть, насколько важно в первую очередь хорошо изучить сам язык. Это поможет написать элегантное решение, не запутавшись в его тонкостях. Для этого вы должны не только знать все элементы и правила языка, но и иметь глубокое понимание их работы.
Ресурсы для изучения:
- «Современный учебник JavaScript» (перевод Ильи Кантора);
- Eloquent JavaScript («Красноречивый JavaScript») (автор Marijn Haverbeke);
- JavaScript Ninja (автор John Resig).
Структуры данных
Если вы не знаете структуры данных, шансов прийти к оптимальному решению (и решению вообще) намного меньше. Поэтому нужно обязательно научиться работать со следующими вещами:
- массивами;
- объектами/Хэш-мапами;
- связанными списками;
- стеками;
- очередями;
- деревьями;
- графами.
Большое О
О большое описывает эффективность выполнения кода — то есть то, насколько быстро выполняется алгоритм с учётом входных данных (time complexity).
После того, как вы напишете свое решение, важно назвать его сложность и время выполнения.
Большое О к задаче пишется комментарием над решением.
Пример:
// O(n) time | O(1) space
Определив эффективность своего кода, обсудите с собеседующим, что еще можно улучшить. По возможности предложите альтернативные способы решения задачи. Это покажет, что вы не просто выдаете заученные варианты, а действительно понимаете, как работает код.
Размышляйте вслух
Перед тем, как начать писать код, задачу нужно решить в уме, проговаривая весь мыслительный процесс. Так вы не запутаетесь, а собеседующий сможет оценить ваш ход мыслей.
Не торопитесь и не сдавайтесь
Одна из частых ошибок – отдавать готовое решение без перепроверки. Перед сдачей работы обязательно пройдитесь по своему коду ещё раз, анализируя его вслух.
Не поддавайтесь панике и не опускайте руки, если подойти к решению никак не получается. Это ещё не конец, и вы всё ещё можете успешно пройти интервью. Обдумайте проблему и попросите у собеседующего небольшую подсказку – это лучше, чем молча сидеть и надеяться, что вам помогут.
Работайте с энтузиазмом
Покажите неподдельную заинтересованность в решении задачи – это разрядит обстановку и облегчит процесс и для вас, и для собеседующего. Почувствуйте азарт, действуйте с пламенем в глазах и пылом в сердце – тогда и сконцентрироваться на задаче будет намного проще.
Задачи уровня Middle
Сумма двух чисел
Напишите функцию, которая принимает два аргумента: массив из уникальных целых чисел и сумму в виде целого числа. Если сумма двух любых чисел массива из аргумента равна числу, которое приходит вторым аргументом, функция должна вернуть новый массив из этих двух чисел в любом порядке. Если решения нет, вернуть пустой массив. Текущее число само с собой складывать нельзя.
Пример входных данных:
На выходе:
[-1, 11]
или [11, -1]
, так как -1 + 11 = 10 = targetSum
Решение 1
Итерируем по массиву и на каждом элементе делаем итерацию по всем последующим элементам, проверяя текущую сумму со следующими на сумму из аргумента.
Решение 2
Мы итерируем по массиву единожды, сохраняя в новом объекте недостаток текущего элемента, нужный для получения targetSum
. На каждой итерации мы проверяем, находится ли текущее значение в объекте остатков. Если да, значит мы уже натыкались в предыдущей итерации на значение, которому не хватало текущего элемента в качестве остатка. Соответственно, мы нашли пару и можем её вернуть.
Преобразование массива в объект с группировкой и фильтрацией элементов
Напишите функцию, которая на вход принимает массив из студентов, где студент — это объект с полями «имя», «возраст» и «номер группы» {name: string, age: number, groupId: number}
, а на выходе возвращает объект, где ключ — это номер группы, а значение — массив из студентов старше 17 лет.
Решение 1
Итерируем по массиву методом высшего порядка reduce
, собирая результат в аккумулирующее значение.
Решение 2
Фирменное решение в одну строчку. Куда же без него!
Если возраст студента меньше 18, возвращаем аккумулятор. Если нет, смотрим, есть ли его id
группы в аккумуляторе. Если есть, значит в аккумуляторе уже есть массив со студентами, следовательно, добавляем этого студента в него, в противном случае создаём новый массив с текущим студентом и добавляем его в аккумулятор под текущим id
группы.
Проверка строки на палиндром
Напишите функцию, которая на вход принимает строку, состоящую из букв нижнего регистра, а на выход возвращает boolean, который отвечает, является ли данная строка палиндромом или нет.
Палиндром — слово или текст, одинаково читающееся в обоих направлениях.
Решение 1
Вариант 1
Вариант 2
- Заводим переменную для хранения результата.
- Проходим циклом по строке с конца, каждый раз конкатенируя текущую букву c ранее заведенной переменной.
- Сравниваем входную строку с перевернутой.
Почему у первого решения time complexity O(n^2), а у второго O(n)?
Причина заключается в том, как JS хранит значения на низком уровне. Из-за того, что строка является примитивным значением, при конкатенации в каждом цикле она заново пересоздается с новым местом в памяти.
Решение 2
- Заводим два пойнтера — для конца и начала строки.
- Идём циклом
while
до тех пор, пока левый пойнтер не пересек правый. - В цикле делаем проверку на несоответствие букв строки по пойнтерам. Если находим неравенство, данная строка не может быть палиндромом, следовательно, мы выходим из функции, возвращая
false
. - Если условие не прошло, то мы сдвигаем оба пойнтера ближе к центру и продолжаем идти по циклу.
- Если мы вышли из цикла, значит строка является палиндромом, и мы возвращаем
true
.
Решение 3
Куда же без однострочного решения? Нет ничего плохо в том, чтобы использовать встроенные функции для быстрого решения задачи, даже если это не максимально эффективно. Но учтите — это не должно быть вашим единственным решением, его можно представить только как дополнение к более эффективным вариантам.
- Разбиваем строку на массив из букв.
- Меняем порядок элементов на обратное направление.
- Соединяем элементы обратно в целую строку.
- WIN!
Найти ближайшее значение в бинарном дереве
Напишите функцию, которая принимает два аргумента — бинарное дерево и значение в виде числа, а возвращает ближайшее значение, найденное в бинарном дереве.
Node = { value: number | null, left: Node | null, right: Node | null }
Решение
Зная свойство сбалансированного бинарного дерева, где слева находятся все значения нод меньше текущей, а справа равные или больше по значению, мы можем в лучшем случае откидывать каждый раз половину дерева.
В данном решении мы идем рекурсивным путём по нодам, записывая и сравнивая разницу со значением из аргумента. Если значение равно нужному, значит мы нашли нужную нам ноду, а иначе мы смотрим, является ли текущее значение ноды меньше или больше того, которое мы ищем. В зависимости от этого мы продолжаем рекурсивно спускаться в нужном нам направлении, обновляя разницу, до тех пор пока не упремся в конец ветки.
Итог
На собеседовании вы можете столкнуться с совершенно другими задачами. Пугаться их не стоит. Основная цель этих заданий в том, чтобы разработчик озвучил свой способ мышления. На ошибки и не до конца реализованную в коде задачу скорее всего закроют глаза. Интервьюеру важно увидеть, как вы рассуждаете, какие подходы используете в зависимости от ситуации, как быстро можете читать и понимать чужой код. Именно на основе этой информации он будет строить с вами дальнейший разговор и принимать решение о найме.
Поэтому дерзайте и удачи на собеседовании ?
37К открытий40К показов