Хочешь уверенно проходить IT-интервью?

Мы понимаем, как сложно подготовиться: стресс, алгоритмы, вопросы, от которых голова идёт кругом. Но с AI тренажёром всё гораздо проще.
💡 Почему Т1 тренажёр — это мастхэв?
- Получишь настоящую обратную связь: где затык, что подтянуть и как стать лучше
- Научишься не только решать задачи, но и объяснять своё решение так, чтобы интервьюер сказал: "Вау!".
- Освоишь все этапы собеседования, от вопросов по алгоритмам до диалога о твоих целях.
Зачем листать миллион туториалов? Просто зайди в Т1 тренажёр, потренируйся и уверенно удиви интервьюеров. Мы не обещаем лёгкой прогулки, но обещаем, что будешь готов!
Реклама. ООО «Смарт Гико», ИНН 7743264341. Erid 2VtzqwP8vqy
Предлагаем вашему вниманию широкий список вопросов, которые могут задать на собеседовании JavaScript-программисту. Все задачи решены на JS, ES5 и ES6.
После каждого решения приведена ссылка на Codepen, где вы можете самостоятельно опробовать решение конкретной задачи.
Массивы
1.1 У вас есть массив целых чисел, найдите наибольшее произведение из трёх чисел данного массива.
var unsortedArray = [-10, 7, 29, 30, 5, -10, -70]; computeProduct(unsortedArray); // 21000 function sortIntegers(a, b) { return a - b; } // Наибольшее произведение - это (min1 * min2 * max1 || max1 * max2 * max3) function computeProduct(unsorted) { var sortedArray = unsorted.sort(sortIntegers), product1 = 1, product2 = 1, array_n_element = sortedArray.length - 1; // Получаем произведение трёх наибольших элементов уже отсортированного массива for (var x = array_n_element; x > array_n_element - 3; x--) { product1 = product1 * sortedArray[x]; } product2 = sortedArray[0] * sortedArray[1] * sortedArray[array_n_element]; if (product1 > product2) return product1; return product2; }
Решение на Codepen: https://codepen.io/kennymkchan/pen/LxoMvm?editors=0012
Нахождение пропущенного элемента
1.2 Неотсортированный массив содержит (n-1) чисел из последовательности {1,2,...,n} (границы определены), найдите недостающий элемент массива за время o(n).
// Число, возвращаемое функцией - 8 var arrayOfIntegers = [2, 5, 1, 4, 9, 6, 3, 7]; var upperBound = 9; var lowerBound = 1; findMissingNumber(arrayOfIntegers, upperBound, lowerBound); // 8 function findMissingNumber(arrayOfIntegers, upperBound, lowerBound) { // Проходим через массив и находим сумму чисел var sumOfIntegers = 0; for (var i = 0; i < arrayOfIntegers.length; i++) { sumOfIntegers += arrayOfIntegers[i]; } /* Находим теоретическую сумму последовательных чисел, используя вариацию суммы Гаусса*/ // Формула: [(N * (N + 1)) / 2] - [(M * (M - 1)) / 2]; // N - верхняя граница, а M - нижняя граница upperLimitSum = (upperBound * (upperBound + 1)) / 2; lowerLimitSum = (lowerBound * (lowerBound - 1)) / 2; theoreticalSum = upperLimitSum - lowerLimitSum; return theoreticalSum - sumOfIntegers; }
Решение на Codepen: http://codepen.io/kennymkchan/pen/rjgoXw?editors=0012
Удаление повторяющихся значений
1.3 Удалите все одинаковые значения в массиве, возвращая массив, состоящий из уникальных элементов.
// Реализация на ES6 var array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8]; Array.from(new Set(array)); // [1, 2, 3, 5, 9, 8] // Реализация на ES5 var array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8]; uniqueArray(array); // [1, 2, 3, 5, 9, 8] function uniqueArray(array) { var hashmap = {}; var unique = []; for(var i = 0; i < array.length; i++) { /* Если возвращаемое значение (unique) - undefined, то оно приравнивается к false. */ if(!hashmap.hasOwnProperty(array[i])) { hashmap[array[i]] = 1; unique.push(array[i]); } } return unique; }
Решение на Codepen: http://codepen.io/kennymkchan/pen/ZLNwze?editors=0012
1.4 У вас есть массив целых чисел, найдите наибольшую разность между такими двумя элементами, что элемент с меньшим значением стоит перед элементом с большим значением.
var array = [7, 8, 4, 9, 9, 15, 3, 1, 10]; // [7, 8, 4, 9, 9, 15, 3, 1, 10] возвращаемое значение будет `11`, как разница между `4` и `15` // Примечание: это не `14`, как разница между `15` и `1`, так как 15 стоит перед 1. findLargestDifference(array); function findLargestDifference(array) { // Если в массиве всего один элемент, то задача не имеет смысла if (array.length <= 1) return -1; // currentMin будет отвечать за наименьший элемент var currentMin = array[0]; var currentMaxDifference = 0; // Мы будем проходить по массиву раз за разом, находя наибольшую разность // Записываем наименьший элемент, так как он впоследствии нам пригодится for (var i = 1; i < array.length; i++) { if (array[i] > currentMin && (array[i] - currentMin > currentMaxDifference)) { currentMaxDifference = array[i] - currentMin; } else if (array[i] <= currentMin) { currentMin = array[i]; } } // Если разность равна нулю или меньше нуля, то задача не имеет смысла if (currentMaxDifference <= 0) return -1; return currentMaxDifference; }
Решение на Codepen: http://codepen.io/kennymkchan/pen/MJdLWJ?editors=0012
И ещё задачи на массивы
1.5 У вас есть массив целых чисел, выведите такой массив, что output[i] равен произведению всех элементов массива за исключением i-ого. (Решите за O(n) без операции деления).
var firstArray = [2, 2, 4, 1]; var secondArray = [0, 0, 0, 2]; var thirdArray = [-2, -2, -3, 2]; productExceptSelf(firstArray); // [8, 8, 4, 16] productExceptSelf(secondArray); // [0, 0, 0, 0] productExceptSelf(thirdArray); // [12, 12, 8, -12] function productExceptSelf(numArray) { var product = 1; var size = numArray.length; var output = []; // Из первого массива: [1, 2, 4, 16] // В данном случае, последний элемент находится уже на правильном // месте, чтобы просто умножить его на 1 в следующем шаге for (var x = 0; x < size; x++) { output.push(product); product = product * numArray[x]; } var product = 1; for (var i = size - 1; i > -1; i--) { output[i] = output[i] * product; product = product * numArray[i]; } return output; }
Решение на Codepen: http://codepen.io/kennymkchan/pen/OWYdJK?editors=0012
Пересечение двух массивов
1.6 Найдите пересечение двух массивов. Пересечение - это общие элементы, которые присутствуют в обоих массивах. Элементы должны быть уникальны.
var firstArray = [2, 2, 4, 1]; var secondArray = [1, 2, 0, 2]; intersection(firstArray, secondArray); // [2, 1] function intersection(firstArray, secondArray) { /* Здесь логика состоит в том, чтобы создать hashmap с элементами первого массива в качестве ключей */ /* После этого вы можете проверить, существует ли элемент в хэше. Сделать это можно за время O(1) благодаря hashmap */ // Если элемент существует, то добавляем его к новому массиву var hashmap = {}; var intersectionArray = []; firstArray.forEach(function(element) { hashmap[element] = 1; }); secondArray.forEach(function(element) { if (hashmap[element] === 1) { intersectionArray.push(element); hashmap[element]++; } }); return intersectionArray; }
Решение на Codepen: http://codepen.io/kennymkchan/pen/vgwbEb?editors=0012
Строки
2.1 У вас есть строка. Ваша задача - перевернуть каждое слово в строке. "Welcome to this Javascript Guide!" должно стать "emocleW ot siht tpircsavaJ !ediuG".
var string = "Welcome to this Javascript Guide!"; // Вывод будет таким: "!ediuG tpircsavaJ siht ot emocleW" var reverseEntireSentence = reverseBySeparator(string, ""); // Вывод будет таким: "emocleW ot siht tpircsavaJ !ediuG" var reverseEachWord = reverseBySeparator(reverseEntireSentence, " "); function reverseBySeparator(string, separator) { return string.split(separator).reverse().join(separator); }
Решение на Codepen: http://codepen.io/kennymkchan/pen/VPOONZ?editors=0012
2.2 У вас есть две строки. Определите, являются ли они анаграммами друг к другу. "Mary" - анаграмм к "Army".
var firstWord = "Mary"; var secondWord = "Army"; isAnagram(firstWord, secondWord); // true function isAnagram(first, second) { // Для удобства переведём все символы в нижний регистр var a = first.toLowerCase(); var b = second.toLowerCase(); /* Отсортируем строки и присоединим финальный массив к строкам. Сравним результаты */ a = a.split("").sort().join(""); b = b.split("").sort().join(""); return a === b; }
Решение на Codepen: http://codepen.io/kennymkchan/pen/NdVVVj?editors=0012
2.3 Проверьте, является ли строка палиндромом. "racecar" - палиндром. "race car" должен тоже считаться за палиндром. Регистр должен учитываться.
isPalindrome("racecar"); // true isPalindrome("race Car"); // true function isPalindrome(word) { // Уберём все символы, не являющиеся буквами var lettersOnly = word.toLowerCase().replace(/\s/g, ""); // Сравним строку с её перевёрнутой версией return lettersOnly === lettersOnly.split("").reverse().join(""); }
Решение на Codepen: http://codepen.io/kennymkchan/pen/xgNNNB?editors=0012
Изоморфные строки
2.4 Проверьте, являются ли две строки изоморфными.
Две строки называются изоморфными, когда в строке A можно заменить конкретный символ на любой другой для получения строки B. Порядок символов должен остаться неизменным. Каждый последовательный символ в строке A сравнивается с каждым последовательным символов в строке B.
'paper' и 'title' вернёт true (p = t, a = i, e = l, r = e).
'egg' и 'sad' вернёт false.
'dgg' и 'add' вернёт true.
isIsomorphic("egg", 'add'); // true isIsomorphic("paper", 'title'); // true isIsomorphic("kick", 'side'); // false function isIsomorphic(firstString, secondString) { /* Проверка на то, имеют ли две строки одинаковую длину. Если нет, то они не изоморфны по определению. */ if (firstString.length !== secondString.length) return false var letterMap = {}; for (var i = 0; i < firstString.length; i++) { var letterA = firstString[i], letterB = secondString[i]; if (letterMap[letterA] === undefined) { letterMap[letterA] = letterB; } else if (letterMap[letterA] !== letterB) { /* Если letterA уже существует, но не указывает на letterB, это значит, что A указывает на больше чем одну букву в строке B. */ return false; } } // Если программа вышла из цикла, значит все условия соблюдены! // Две строки изоморфны! return true; }
Решение на Codepen: http://codepen.io/kennymkchan/pen/mRZgaj?editors=0012
Стэки и очереди
3.1 Реализуйте два метода: enqueue и dequeue, используя только два стэка
var inputStack = []; // Первый стэк var outputStack = []; // Второй стэк // Для реализации enqueue просто сделаем push в первый стэк function enqueue(stackInput, item) { return stackInput.push(item); } function dequeue(stackInput, stackOutput) { /* Перевернём стэк таким образом, что первый элемент выходного стэка - последний элемента входного. После этого делаем pop выходного стэка */ if (stackOutput.length <= 0) { while(stackInput.length > 0) { var elementToOutput = stackInput.pop(); stackOutput.push(elementToOutput); } } return stackOutput.pop(); }
Решение на Codepen: http://codepen.io/kennymkchan/pen/mRYYZV?editors=0012
3.2 Напишите функцию, которая будет проверять, являются ли фигурные скобки сбалансированными, используя стэки. {} - считается блоком. {}{} - сбалансированные скобки. {{{}} - несбалансированные.
var expression = "{{}}{}{}" var expressionFalse = "{}{{}"; isBalanced(expression); // true isBalanced(expressionFalse); // false isBalanced(""); // true function isBalanced(expression) { var checkString = expression; var stack = []; // Если входная строка пуста, то технически всё сбалансировано if (checkString.length <= 0) return true; for (var i = 0; i < checkString.length; i++) { if(checkString[i] === '{') { stack.push(checkString[i]); } else if (checkString[i] === '}') { if (stack.length > 0) { stack.pop(); } else { return false; } } } if (stack.pop()) return false; return true; }
Решение на Codepen: http://codepen.io/kennymkchan/pen/egaawj?editors=0012
Рекурсия
4.1 Напишите рекурсивную функцию, которая переводит десятичное число в двоичное. Если входное число - 4, выходным будет 100.
decimalToBinary(3); // 11 decimalToBinary(8); // 1000 decimalToBinary(1000); // 1111101000 function decimalToBinary(digit) { if(digit >= 1) { if (digit % 2) { return decimalToBinary((digit - 1) / 2) + 1; } else { return decimalToBinary(digit / 2) + 0; } } else { return ''; } }
Решение на Codepen: http://codepen.io/kennymkchan/pen/OWYYKb?editors=0012
4.2 Напишите рекурсивную функцию, которая выполняет бинарный поиск
function recursiveBinarySearch(array, value, leftPosition, rightPosition) { // Value DNE if (leftPosition > rightPosition) return -1; var middlePivot = Math.floor((leftPosition + rightPosition) / 2); if (array[middlePivot] === value) { return middlePivot; } else if (array[middlePivot] > value) { return recursiveBinarySearch(array, value, leftPosition, middlePivot - 1); } else { return recursiveBinarySearch(array, value, middlePivot + 1, rightPosition); } }
Решение на Codepen: http://codepen.io/kennymkchan/pen/ygWWmK?editors=0012
Числа
5.1 У вас есть целое число, определите, является ли оно является степенью двойки.
isPowerOfTwo(4); // true isPowerOfTwo(64); // true isPowerOfTwo(1); // true isPowerOfTwo(0); // false isPowerOfTwo(-1); // false //Без проверки на ноль function isPowerOfTwo(number) { // `&` ипользует побитовую запись n. // В данном случае, входное число - 4; выражение идентично: // `return (4 & 3 === 0)` /* 4 в двоичном виде - 100, а 3 - 011. & проверяет на то, чтобы оба числа в двоичном виде имели еденицу на одном и том же месте. В таком случае будет возвращено 1, иначе - 0. В этом случае, результатом будет 000. */ // таким образом, 4 удовлетворяет условиям. return number & (number - 1) === 0; } //С проверкой на ноль function isPowerOfTwoZeroCase(number) { return (number !== 0) && ((number & (number - 1)) === 0); }
Решение на Codepen: http://codepen.io/kennymkchan/pen/qRGGeG?editors=0012
JavaScript
6.1 Объясните, что такое "поднятие" в JavaScript.
"Поднятие" - это правило, которое подразумевает под собой необходимость перемещать все объявления переменных в вершину конкретного блока кода. Это касается объявления переменных, инициализация же может проходить и дальше в коде.
6.2 Объясните функционал директивы use strict;
директива use strict; говорит о том, что код должен быть выполнен в "строгом режиме". Один из плюсов данного режима - это то, что он предотвращает использование необъявленных переменных. Наиболее старые версии JavaScript будут игнорировать данную директиву.
// Пример "строгого режима" "use strict"; catchThemAll(); function catchThemAll() { x = 3.14; // На этом моменте будет ошибка return x * x; }
6.3 Объясните, что такое event bubbling и как его предотвратить.
Even bubbling - это концепт, при котором порядок выполнения событий должен подниматься по структуре DOM-дерева.
Один из вариантов предотвращения - "event.stopPropagation()" или "event.cancelBubble", для IE версии ниже 9.
6.4 Какова разница между == и === в JavaScript?
=== известен как строгий оператор. Ключевая разница между == и === - это то, что == сравнивает лишь значения, а === - ещё и типы данных.
// Пример "==" и "===". 0 == false; // true 0 === false; // false 2 == '2'; // true 2 === '2'; // false
6.5 Какова разница между null и undefined?
Null в JavaScript может быть присвоен переменной, а undefined лишь показывает, что переменная была объявлена, но не была инициализирована.
6.6 В чём разница между прототипным наследованием и классическим наследованием?
В классическом наследовании классы неизменны, поддерживают множественное наследование, могут содержать интерфейсы, final классы и abstract классы. Прототипы же куда более гибки в том плане, что они могут быть изменены.
Другие статьи по теме
Подборка материалов по JavaScript
10 вещей, которые стоит знать каждому JavaScript-разработчику
Комментарии