Всем привет! Сейчас без live-coding'a никуда: на собеседованиях часто дают одну-две задачки, которые нужно решить за определённое время. Сами задачи могут быть несложными (не супер-пупер алгоритмическими), но новички могут переволноваться и не справиться с ними.

Поэтому в этой статье я хотел бы описать типовые задачи, которые встречаются в этой секции на позицию frontend или backend разработчика (если бэк на JS). Это поможет вам получить общее представление о том, что может ждать вас. Не забываем подписываться на мой канал в Telegram, там тоже есть, что почитать.

Поеееехалииии ?️?

Понимание JavaScript

Чтобы решать задачки, необходимо хорошо знать основы JS. Здесь я хочу выделить следующие темы:

  • Переменные, типы данных (особенно строки).

  • Простые операторы (+, -, *, /, %, >, < и тд) и побитовые (&, |, ~, <<, >>, >>>).

  • Условный оператор, циклы (особенно уметь использовать while и for.

  • Функции. Рекурсия - очень важная концепция. Иногда встречаются задачи, которые можно решить только с её помощью. Также не менее важно понимать замыкания, контекст выполнения и области видимости.

  • Структуры данных - массивы (80% задач), объекты/мапы/хэш-таблицы.

  • Регулярные выражения.

Как говорится это база. Идем дальше ?

Подходы к решению задач в секции live-coding

Рассмотри основной алгоритм решения задач:

  1. Понимание задачи - убедитесь, что вы понимаете задачу, какие входные данные, ограничения. Если этого всего нет, задавайте вопросы, вас точно проверят на то, как вы собираете требования.

  2. Планирование решения - быстро набросайте структуру решения вашей задачи, какой-то алгоритм. Обязательно проговаривайте свое решение, чтобы его слышали.

  3. Решаем задачу в лоб, проверяем работает ли он на исходных данных. Если все ок, то только потом пытаемся ее оптимизировать.

  4. Сразу подумайте о граничных тестах: пустые данные, большие объемы, минимальные и максимальные значения.

  5. Опять тестируем - используйте предоставленные примеры, а также создавайте свои тестовые случаи.

  6. Исправляем, рефакторим, тестируем.

  7. Говорим, что готово.

Главное - не нервничать и задавать вопросы, если что-то остаётся непонятным. Кстати, это также поможет вам понять, сможете ли вы работать с этим человеком в будущем. Если на ваши вопросы следуют глубокие вздохи или полное молчание, это уже ред флаг.

В бой

Давайте перейдем к самому интересному - к задачкам. К каждой задаче я подготовил решение, но настоятельно советую сначала решить, а потом уже посмотреть решение. Весь исходный код будет расположен на 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
Ответ

Напишите функцию, определяющую, является ли данное число полным квадратом.

// Тестовые данные
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, где я делюсь интересной и полезной информацией.

Комментарии (23)


  1. alex_k777
    01.02.2025 11:31

    Терпеть не могу, когда наблюдают за тем, как я пишу код. Почему без этого никуда? Какой процент компаний используют live-coding при собеседовании? Я встречал только одну и отказался сразу от такого собеседования.


    1. altrapeznikov Автор
      01.02.2025 11:31

      К сожалению, почти все крупные компании...


    1. ermouth
      01.02.2025 11:31

      Потому что есть ребята, которые рисуют себе толстый опыт, а потом оказывается, что они синтаксис цикла for «не помнят».


      1. Korund
        01.02.2025 11:31

        А если я честно говорю, что у меня нет опыта, но многие задачи из поста, я могу решить, но мне действительно некоторый синтаксис надо погуглить. С такими навыками я остаюсь за бортом или могу рассчитывать на условную позицию джуна?


  1. FODD
    01.02.2025 11:31

    isPalindrome имеет менее многословное решение

    function isPalindrome(str) {
      const transormed = str.replace(/[^\w]/g, '').toLocaleLowerCase();
      return transormed === transormed.split('').reverse().join('')
    }
    


    1. sharpfellow
      01.02.2025 11:31

      При таком решении можно ожидать дополнение от интервьюера

      "Что будет при выполнении, если str занимает 90% доступной памяти?"


    1. Andreyika
      01.02.2025 11:31

      есть еще менее многословное

      $.isPalindrome(str)
      

      в более модном-молодежном варианте:

      yarn add @huynhducduy/is-palindrome

      function _isPalindrome(str) {
       return isPalindrome(str)
      }
      


      1. adminNiochen
        01.02.2025 11:31

        Так про любую задачу можно ответить: гуглим пакет, в котором есть данная функция и устанавливаем его.


  1. SergeiZababurin
    01.02.2025 11:31

    Ни на одной работе с лайв кодингом не сталкивался. Это для меня признак компании в которой не стоит работать и некомпетентности вопрошающего.


    1. barmaglot92
      01.02.2025 11:31

      Ни одной вакансии не видел без Лив кодинга, работал в Яндекс ВТБ сбер


      1. SergeiZababurin
        01.02.2025 11:31

        Альпари (туда из втб кстати тоже приходили) perfect centr и последняя. Везде особенность в том, что стек может быть любой. Этот лайв кодинг как мертвому припарка. Главное выполнять задачи уметь. На extjs drupal vue react wordpres, backbone что нибудь на php, и все без разницы. Писал ты или нет на этих фреймворках, при том, что стиль написания в каждом проекте свой. Проблемы у фронтенд разработчика как правило не связанны с программированием.


        1. altrapeznikov Автор
          01.02.2025 11:31

          А c чем же тогда? со стилями?


    1. ArturKD
      01.02.2025 11:31

      На аутсорсе заказчик может собесить с лайвом и никуда от этого не денешься. У меня, например, беда с этим, поэтому хочу придумать себе какую-то практику что-ли.


      1. altrapeznikov Автор
        01.02.2025 11:31

        Главное - тренироваться каждый день, одну задачку, например, перед сном :)


    1. adminNiochen
      01.02.2025 11:31

      Это почему же? Тебе же не дают тестовое сделать, потратив n часов своего времени на код, который неизвестно посмотрят вообще или нет. На лайвкодинге дают задачи, которые можно решить за 5-10 мин в плане сложности - и смотрят даже не на ответ, а на ход рассуждений. Это может не нравиться если ты например не умеешь думать...


      1. SergeiZababurin
        01.02.2025 11:31

        Ни на одном собеседовании код не давали. Тоже считаю это трата моего времени. Если человек не способен оценить твои знание по разговору, у него скорее всего нет возможности оценить и то что ты написал.

        На всех собеседованиях просто говорили. Я один раз только тестовое задание сделал и то потому что мне надо было табличку такую для себя делать. И это было русской компании после начала сво. Проект кстати так и не дошел до сдачи. Но я свою часть хорошо сделал, по этому это мне помогло устроиться на другую работу потом.

        Может быть сейчас что то поменялось...
        Если так, я в будущем рассмотрю тогда лучше вариант работать курьером и писать свой проект.

        Одно дело работать с людьми которые для тебя авторитеты, другое дело с не пойми кем, кто требует от тебя не пойми что


  1. NN1
    01.02.2025 11:31

    Не надо советовать ответ с рекурсией.

    Следующим вопросом будет как решить глубину рекурсии.


    1. GospodinKolhoznik
      01.02.2025 11:31

      А нет никакой проблемы. Расход памяти при вызове рекурсии линейно зависит от глубины рекурсии. А рост ёмкости ОЗУ из за технического прогресса идёт по экспоненте. Может показаться, что рекурсивный алгорит сожрёт память гораздо быстрее, чем период времени в течении которого происходит апгрейд ОЗУ у компьютера. Но это лишь на малых временных интервалах, а в ассимптотике увеличение памяти при апгрейде будет расти несоизмеримо быстрее расхода памяти, т.к. O(exp(t)) >> O(t) и память никогда не закончится =)))


      1. NN1
        01.02.2025 11:31

        В том и дело, что кончается очень быстро.

        Обычно на каждый поток выделяется 1МБ памяти.

        Под переменные ну скажем нужно 24 байт стека и 8 на возврат итого каждый вызов 32 байта .

        1МБ/32=32768 рекурсивных вызовов пока прогнозами а не упадёт.

        Не так много.


        1. cupraer
          01.02.2025 11:31

          Я, конечно, понимаю, что про такие штуки, как TCO, в джаваскрипте никогда не думали — нечего и начинать, но вот неглупые ребята же все-таки существуют: https://glat.info/pub/tailopt-js/

          Проблемы переполнения стека при рекурсивных но хвостовых вызовах — были решены академически примерно 50 лет назад. Хвостовая рекурсия всегда может быть развёрнута в цикл.

          Так что все нормально с рекурсией, если знать, как её готовить.


  1. IvanZaycev0717
    01.02.2025 11:31

    Что-то слишком простые задачи, тут грейд "junior" не выше (по современным стандартам). Если на более высокий грейд будут такие задачи - это просто неописуемая удача.

    У меня был live-coding на собеседованиях (правда только на Python), и там была одна задача на Two Pointers, и ещё одна на DFS - навык решения таких задач набивается на LeetCode. Two Pointers просто надо понять смысл, а DFS - зубрить и понимать, что присходит.

    Всем желающим набить навык live coding, я посоветовал бы начать с задачника Абрамяна М.Э. "1000 задач по программированию". Там задачи можно решать на абсолютно любом языке. Там такие же задачи как в статье. Когда вам станет решать эти задачи "как нечего делать", тогда переходим на LeetCode


  1. Maxkuku
    01.02.2025 11:31

    Я считаю, что sumRange.js - это излишне перемудрёное. Зачем усложнять простые действия, которые трудно прослеить?


  1. Tobiass
    01.02.2025 11:31

    Задача 2.
    Напишите функцию, которая переворачивает цифры числа, сохраняя знак нетронутым.

    Вы используете для решения строковые операции. Хотя куда эффективнее будет использовать арифметические операции. Ниже решение
    function reverseNumber(num) {
    const isNegative = num < 0; if (isNegative) { num = Math.abs(num); } let reversed = 0; while (num !== 0) { const lastDigit = num % 10; reversed = reversed * 10 + lastDigit; num = Math.floor(num / 10); } return isNegative ? -reversed : reversed; }
    Не то, что я умничать пытаюсь... Просто эта задача уже классика LeetCode и ему подобных)