JavaScript. Готовимся к live-coding
- воскресенье, 2 февраля 2025 г. в 00:00:05
Всем привет! Сейчас без live-coding'a никуда: на собеседованиях часто дают одну-две задачки, которые нужно решить за определённое время. Сами задачи могут быть несложными (не супер-пупер алгоритмическими), но новички могут переволноваться и не справиться с ними.
Поэтому в этой статье я хотел бы описать типовые задачи, которые встречаются в этой секции на позицию frontend или backend разработчика (если бэк на JS). Это поможет вам получить общее представление о том, что может ждать вас. Не забываем подписываться на мой канал в Telegram, там тоже есть, что почитать.
Поеееехалииии 🏎️💨
Чтобы решать задачки, необходимо хорошо знать основы JS. Здесь я хочу выделить следующие темы:
Переменные, типы данных (особенно строки).
Простые операторы (+, -, *, /, %, >, < и тд) и побитовые (&, |, ~, <<, >>, >>>).
Условный оператор, циклы (особенно уметь использовать while и for.
Функции. Рекурсия - очень важная концепция. Иногда встречаются задачи, которые можно решить только с её помощью. Также не менее важно понимать замыкания, контекст выполнения и области видимости.
Структуры данных - массивы (80% задач), объекты/мапы/хэш-таблицы.
Регулярные выражения.
Как говорится это база. Идем дальше 🚀
Рассмотри основной алгоритм решения задач:
Понимание задачи - убедитесь, что вы понимаете задачу, какие входные данные, ограничения. Если этого всего нет, задавайте вопросы, вас точно проверят на то, как вы собираете требования.
Планирование решения - быстро набросайте структуру решения вашей задачи, какой-то алгоритм. Обязательно проговаривайте свое решение, чтобы его слышали.
Решаем задачу в лоб, проверяем работает ли он на исходных данных. Если все ок, то только потом пытаемся ее оптимизировать.
Сразу подумайте о граничных тестах: пустые данные, большие объемы, минимальные и максимальные значения.
Опять тестируем - используйте предоставленные примеры, а также создавайте свои тестовые случаи.
Исправляем, рефакторим, тестируем.
Говорим, что готово.
Главное - не нервничать и задавать вопросы, если что-то остаётся непонятным. Кстати, это также поможет вам понять, сможете ли вы работать с этим человеком в будущем. Если на ваши вопросы следуют глубокие вздохи или полное молчание, это уже ред флаг.
Давайте перейдем к самому интересному - к задачкам. К каждой задаче я подготовил решение, но настоятельно советую сначала решить, а потом уже посмотреть решение. Весь исходный код будет расположен на GitHub (ссылка в конце статьи) и будет пополняться!
Простые задачи
Функция
sumRange
принимает два числаstart
иend
. Необходимо найти сумму всех чисел в заданном диапазоне.
// Тестовые данные
console.log(sumRange(1, 5)); // 15
console.log(sumRange(0, 10)); // 55
console.log(sumRange(-3, 3)); // 0
Напишите функцию, которая переворачивает цифры числа, сохраняя знак нетронутым.
// Тестовые данные
console.log(reverseNumber(123)); // 321
console.log(reverseNumber(-456)); // -654
console.log(reverseNumber(1000)); // 1
console.log(reverseNumber(0)); // 0
https://github.com/atrapeznikov/live-coding/blob/main/reverseNumber.js
Напишите функцию, определяющую, является ли данное число полным квадратом.
// Тестовые данные
console.log(isPerfectSquare(16)); // true
console.log(isPerfectSquare(14)); // false
console.log(isPerfectSquare(0)); // true
console.log(isPerfectSquare(25)); // true
Массивы
Реализовать функцию
minMax()
, которая принимает массив и возвращает максимальное и минимальное значение. Решить нужно не используюMath.min()
иMath.max()
.
// Тестовые данные
console.log(findMinMax([4, 3, 5, 3, 2])); // {min: 2, max: 5}
console.log(findMinMax([4, 4, 7, 2, 1, 10])); // {min: 1, max: 10}
console.log(findMinMax([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // {min: 1, max: 10}
Необходимо в массиве найти второе наибольшее число.
// Тестовые данные
console.log(secondLargest([10, 20, 4, 45, 99])); // 45
console.log(secondLargest([5, 5, 5])); // null
console.log(secondLargest([1])); // null
Напишите функцию, которая возвращает все пары чисел из массива, сумма которых равна заданной целевой сумме.
// Тестовые данные
console.log(findPairs([2, 4, 3, 7, 8, 1], 9)); // [[7, 2], [8, 1]]
console.log(findPairs([1, 2, 3, 4, 5], 10)); // []
console.log(findPairs([0, -1, -2, 2, 1], 0)); // [[-1, 1], [-2, 2]]
Строки
Проверить, является ли заданная строка палиндромом. Необходимо игнорировать символы пробела, знаков препинания и пр.
// Тестовые данные
console.log(isPalindrome("A man, a plan, a canal, Panama!")); // true
console.log(isPalindrome("No 'x' in Nixon")); // true
console.log(isPalindrome("Was it a car or a cat I saw?")); // true
console.log(isPalindrome("Eva, I see bees in a cave")); // false
Напишите функцию, проверяющую, являются ли две строки анаграммами друг друга (регистр букв не имеет значения)
// Тестовые данные
console.log(isAnagram("finder", "Friend")); // true
console.log(isAnagram("hello", "bye")); // false
console.log(isAnagram("listen", "silent")); // true
console.log(isAnagram("rail safety", "fairy tales"));
Напишите функцию для поиска первого неповторяющегося символа в строке. Возвращайте ноль (
null
), если все символы повторяются.
// Тестовые данные
console.log(firstNonRepeatingChar("swiss")); // "w"
console.log(firstNonRepeatingChar("aabbcc")); // null
console.log(firstNonRepeatingChar("javascript")); // "j"
Напишите функцию для подсчета количества гласных и согласных в строке.
// Тестовые данные
console.log(countVowelsAndConsonants("hello")); // { vowels: 2, consonants: 3 }
console.log(countVowelsAndConsonants("JavaScript")); // { vowels: 3, consonants: 7 }
console.log(countVowelsAndConsonants("12345")); // { vowels: 0, consonants: 0 }
Рекурсия
Напишите функцию, которая вычисляет факториал числа.
// Тестовые данные
console.log(factorial(0)); // 1
console.log(factorial(1)); // 1
console.log(factorial(2)); // 2
console.log(factorial(3)); // 6
Необходимо написать функцию которая превращает многомерный массив в одномерный.
// Тестовые данные
console.log(_flatten([1, 2, 3])); // [1, 2, 3]
console.log(_flatten([1, [2, 3], 4])); // [1, 2, 3, 4]
console.log(_flatten([[1, 2], [3, 4]])); // [1, 2, 3, 4]
console.log(_flatten([1, [2, [3, [4, 5]]]])); // [1, 2, 3, 4, 5]
console.log(_flatten([])); // []
Написать функцию которая возвращает последовательность фибоначи.
// Тестовые данные
console.log(fibonacci(0)); // 0
console.log(fibonacci(1)); // 1
console.log(fibonacci(2)); // 1
Напишите рекурсивную функцию для определения длины строки.
// Тестовые данные
console.log(stringLength("hello")); // 5
console.log(stringLength("JavaScript")); // 10
console.log(stringLength("")); // 0
Напишите рекурсивную функцию для поиска максимального элемента в массиве.
// Тестовые данные
console.log(findMax([1, 5, 3, 9, 2])); // 9
console.log(findMax([-1, -5, -3])); // -1
console.log(findMax([10])); // 10
Асинхронные операции
Необходимо создать функцию
fetchRetryer()
, которая будет выполнять запрос на определенный API и повторять его до 5 раз, пока не получит ответ (статус 200). Если после 5 повторов сервер не отвечает - возвращаем ошибку.
// Пример использования
fetchRetryer("https://jsonplaceholder.typicode.com/posts/1")
.then((res) => res.json())
.then((data) => console.log("Success:", data))
.catch((err) => console.error("Failed:", err.message));
fetchRetryer("https://invalid-url.example")
.then((res) => res.json())
.catch((err) => console.error("Failed after retries:", err.message));
Реализуйте функцию
_promiseAll
.
// Тестовые данные
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
const promise4 = new Promise((resolve) => setTimeout(resolve, 100, 4));
_promiseAll([promise1, promise2, promise3, promise4])
.then((results) => {
console.log(results); // Output: [1, 2, 3, 4]
})
.catch((error) => {
console.error(error);
});
const promise5 = Promise.reject("Error occurred");
customPromiseAll([promise1, promise2, promise5])
.then((results) => {
console.log(results);
})
.catch((error) => {
console.error(error); // Output: Error occurred
});
Необходимо написать функцию, которая принимает два аргумента: асинхронную функцию и временной лимит в миллисекундах. Эта функция должна возвращать новую версию асинхронной функции, выполнение которой ограничено заданным временным лимитом.
Должны выполняться следующие условия:
Если время выполнения исходной функции меньше временного лимита, новая функция должна вернуть результат выполнения асинхронной функции.
Если время выполнения исходной функции превышает временной лимит, новая функция должна вернуть сообщение: "Превышен лимит исполнения".
// Тестовые данные
const fn = async (n) => {
await new Promise((res) => setTimeout(res, 100));
return n * n;
};
console.log(asyncLimit(fn, 50)(5)); // rejected превышен лимит
console.log(asyncLimit(fn, 150)(5)); // resolve 25
const fn2 = async (a, b) => {
await new Promise((res) => setTimeout(res, 120));
return a + b;
};
console.log(asyncLimit(fn2, 100)(1, 2));
console.log(asyncLimit(fn2, 150)(1, 2));
Реализация встроенных функций (полифилы)
Реализуйте метод
_filter
для массивов.
// Тестовые данные
console.log([1, 2, 3, 4, 5]._filter(n => n % 2 === 0)); // [2, 4]
console.log(["apple", "banana", "cherry"]._filter(fruit => fruit.includes("a"))); // ["apple", "banana"]
console.log([10, 20, 30]._filter((num, index) => index % 2 === 0)); // [10, 30]
Реализуйте метод
_map
для массивов.
// Тестовые данные
console.log([1, 2, 3]._map(n => n * 2)); // [2, 4, 6]
console.log(["a", "b", "c"]._map(letter => letter.toUpperCase())); // ["A", "B", "C"]
console.log([10, 20, 30]._map((num, index) => num + index)); // [10, 21, 32]
Реализуйте метод
_reduce
для массивов.
// Тестовые данные
console.log([1, 2, 3, 4]._reduce((acc, num) => acc + num)); // 10
console.log([1, 2, 3, 4]._reduce((acc, num) => acc + num, 10)); // 20
console.log(["a", "b", "c"]._reduce((acc, char) => acc + char)); // "abc"
console.log([2, 3, 4]._reduce((acc, num) => acc * num, 1)); // 24
Реализуйте класс
EventEmitter.
// Пример использования
const emitter = new EventEmitter();
function responseToEvent(data) {
console.log(`Event received with data: ${data}`);
}
emitter.on('dataReceived', responseToEvent);
emitter.emit('dataReceived', { id: 1, message: 'Hello, World!' });
emitter.off('dataReceived', responseToEvent);
emitter.emit('dataReceived', { id: 2, message: 'This will not be logged.' });
// Register a one-time event listener
emitter.once('dataReceivedOnce', (data) => {
console.log(`One-time event received: ${data}`);
});
emitter.emit('dataReceivedOnce', 'This will be logged once.');
emitter.emit('dataReceivedOnce', 'This will not be logged.');
Регулярные выражения
Напишите функцию, которая принимает строку в качестве аргумента и возвращает количество гласных, содержащихся в этой строке. Гласными являются «a», «e», «i», «o», «u».
// Тестовые данные
console.log(countVowels("hello")); // 2
console.log(countVowels("JavaScript")); // 3
console.log(countVowels("xyz")); // 0
Напишите функцию для извлечения доменных имен из URL-адресов, используя регулярные выражения.
// Тестовые данные
console.log(extractDomain("https://www.google.com")); // "google.com"
console.log(extractDomain("http://example.org")); // "example.org"
console.log(extractDomain("https://sub.domain.com/path")); // "sub.domain.com"
console.log(extractDomain("invalid-url")); // null
Дополнительные задачи
Написать функцию, которая проверит строку и вернёт в результате
true
илиfalse
в зависимости от того, является ли данная последовательность скобок валидной.
// Тестовые данные
console.log(isValidParentheses("()[]{}")); // true
console.log(isValidParentheses("([{}])")); // true
console.log(isValidParentheses("(]")); // false
console.log(isValidParentheses("([)]")); // false
console.log(isValidParentheses("{[]}")); // true
Разработайте стек, который поддерживает операции
push
,pop
,top
и извлечение минимального элемента за постоянное время O(1).
// Пример использования
const minStack = new MinStack();
minStack.push(5);
minStack.push(3);
minStack.push(7);
console.log(minStack.getMin());
minStack.pop();
console.log(minStack.getMin());
minStack.pop();
console.log(minStack.getMin());
Напишите функцию, которая принимает массив строк (логи) и возвращает список пользователей, которые больше всего взаимодействовали с системой.
// Пример использования:
const logs = [
"user1 login",
"user2 login",
"user1 click",
"user3 login",
"user1 logout",
"user2 click",
"user2 logout",
"user3 click",
"user3 logout",
];
console.log(analyzeLogs(logs));
// { user1: 3, user2: 3, user3: 3 }
Реализуйте функцию, которая запускает задачи с ограничением на количество параллельно выполняемых задач.
// Пример использования:
const tasks = [
() => new Promise((res) => setTimeout(() => res("Task 1"), 1000)),
() => new Promise((res) => setTimeout(() => res("Task 2"), 500)),
() => new Promise((res) => setTimeout(() => res("Task 3"), 1200)),
() => new Promise((res) => setTimeout(() => res("Task 4"), 300)),
];
parallelTaskRunner(tasks, 2).then(console.log);
// ["Task 1", "Task 2", "Task 3", "Task 4"]
Ну вот, мы рассмотрели типовые задачи. Конечно, это далеко не всё, что может встретиться вам на собеседовании. Я планирую добавлять ещё задачи в этот репозиторий, так что переходите по ссылке и сохраняйте!
Не забывайте, что успешное выполнение задач в секции live-coding требует постоянной практики и упорства. Формула проста: чем больше вы практикуетесь, тем увереннее будете себя чувствовать на собеседованиях. Всё просто!
Желаю вам удачи!
📢 Подписывайтесь на мой канал в Telegram, где я делюсь интересной и полезной информацией.