5 типични задачи на интервюта за JavaScript: анализ и решения

5 типични задачи на интервюта за JavaScript: анализ и решения

От преводача: публикувахме за вас статия Мария Перна (Maria Antonietta Perna), която разказва за типичните задачи по JavaScript, най-често предлагани на кандидатите за разработчици по време на интервюта. Статията ще бъде полезна преди всичко на начинаещите програмисти.

Интервютата в технологичните компании отдавна са притча на устатa. Не е чудно — успешното преминаване на интервюто дава възможност за получаване на добра работа. Но това не е толкова просто, тъй като често е необходимо да се решават сложни задачи.

В повечето случаи повечето от тези задачи нямат отношение към работата, която кандидатът ще изпълнява, но все пак трябва да се решават. Понякога се налага да го правите на дъска, без да се допитвате до Google или друг източник. Да, ситуацията постепенно се променя, и в някои компании се отказват от такива интервюта, но много работодатели все още спазват тази традиция. Тази статия е посветена на анализа на типични JavaScript задачи, които често се използват като задания за кандидатите.

Напомняме: за всички читатели на "Хабра" — отстъпка от 10 000 рубли при записване на всякакъв курс на Skillbox с промокод "Хабр".

Skillbox препоръчва: Практически курс «Мобилен разработчик PRO».

Основното е старателната подготовка за вашето интервю

Да, преди да започнем да обсъждаме задачите, нека разгледаме общите съвети за подготовка за интервюто.

Основното е да се подготвите предварително. Проверете колко добре помните алгоритмите и структурите от данни, и усъвършенствайте знанията си в областите, които не са ви особено познати. Има много онлайн платформи, които ще помогнат с подготовката за интервютата. Препоръчваме GeeksforGeeks, Pramp, Interviewing.io и CodeSignal.

Трябва да се научите да изговаряте решението на глас. Препоръчително е да разказвате на интервюиращия какво правите, а не просто да пишете на дъска (или да генерирате код на компютър, също мълчаливо). По този начин, ако в кода допуснете грешка, но ходът на решението е основно правилен, можете да увеличите шансовете си за успех.

Задачата трябва да се осмисли, преди да се премине към решението. В някои случаи можете повърхностно да разберете задачата и след това да поемете по грешния път. Може би си струва да зададете няколко уточняващи въпроса на интервюиращия.

Трябва да се упражнявате да пишете код на ръка, а не на компютър. Понякога по време на интервюта кандидатът получава маркер и дъска, на която няма нито подсказки, нито автоматично форматиране. Когато търсите решение, е добре да запишете кода си на лист хартия или директно на дъската. Ако всичко държите в главата си, можете да забравите нещо важно.

Шаблонни задачи за JavaScript

Вероятно някои от тези задачи вече са ви познати. Либо сте участвали в интервюта, на които е необходимо да решите нещо подобно, либо сте практикували с тях по време на изучаването на JavaScript. Сега обаче е време да ги решите отново, и то с подробно обяснение на процеса.

Палиндром

Палиндром е дума, изречение или последователност от символи, които се четат абсолютно еднакво както в обичайната посока, така и в обратната. Например, "Анна" е палиндром, докато "маса" и "Джон" не са.

Постановка

Дадена е строка; необходимо е да напишете функция, която да върне стойност true, ако строката е палиндром, и false, ако не е. При това трябва да се вземат предвид интервалите и пунктуацията.

palindrome('racecar') === true
palindrome('mаса') === false

Разглеждаме задачата

Основната идея тук е да обърнем строката в обратна посока. Ако "обратната" строка е напълно идентична на оригиналната, значи сме получили палиндром и функцията трябва да върне стойност true. В противен случай — false.

Решение

Ето кодът, който позволява да решим задачата с палиндром.

const palindrome = str => {
  // обръщане на строката в малки букви
  str = str.toLowerCase()
  // обръщане на входната строка и връщане на резултата от
  // сравняването
  return str === str.split('').reverse().join('')
}

Първата стъпка е преобразуването на символите на входната строка в малки букви. Това гарантира, че програмата ще сравнява именно самите символи, а не регистъра или нещо друго.

Втората стъпка е обръщането на строката. Това не е сложно: необходимо е да я преобразуваме в масив с метода .split() (библиотеката String). След това обръщаме масива, използвайки .reverse() (библиотеката Array). Последната стъпка е преобразуването на обратния масив в строка с помощта на .join() (библиотеката Array).

Сега всичко, което трябва да направите, е да сравните "обратната" строка с оригиналната, връщайки резултата true или false.

FizzBuzz

Една от най-популярните задачи на интервютата.

Постановка

Необходимо е да напишете функция, която да извежда в конзолата числата от 1 до n, където n е цяло число, което функцията приема като параметър, с такива условия:

  • извежда fizz вместо числа, кратни на 3;
  • извеждане на buzz вместо числа, кратни на 5;
  • извеждане на fizzbuzz вместо числа, кратни и на 3, и на 5.

Пример

Fizzbuzz(5)

Резултат

// 1
// 2
// fizz
// 4
// buzz

Разглеждаме задачата

Основното тук е начинът за намиране на кратни числа с помощта на JavaScript. Това може да се реализира посредством оператора за остатък — %, който показва остатъка при деление на две числа. Ако остатъкът е 0, това означава, че първото число е кратно на второто.

12 % 5 // 2 -> 12 не е кратно на 5
12 % 3 // 0 -> 12 е кратно на 3

Така, ако разделим 12 на 5, получаваме 2 с остатък 2. Ако разделим 12 на 3, получаваме 4 с остатък 0. В първия случай 12 не е кратно на 5, а във втория — 12 е кратно на 3.

Решение

Оптималното решение ще бъде следния код:

const fizzBuzz = num => {
  for(let i = 1; i <= num; i++) {
    // проверка дали числото е кратно на 3 и 5
    if(i % 3 === 0 && i % 5 === 0) {
      console.log('fizzbuzz')
    } // проверка дали числото е кратно на 3
      else if(i % 3 === 0) {
      console.log('fizz')
    } // проверка дали числото е кратно на 5
      else if(i % 5 === 0) {
      console.log('buzz')
    } else {
      console.log(i)
    }
  }
}

Функцията извършва необходимите проверки с помощта на условни оператори и дава резултат, необходим на потребителя. В задачата е важно да се обърне внимание на реда на операторите if…else: започва се с двойното условие (&&) и завършва със случая, когато кратни числа не са намерени. В резултат обхващаме всички варианти.

Анаграмa

Това е дума, която съдържа всички букви на друга дума в същото количество, но в различен ред.

Постановка

Необходимо е да се напише функция, която проверява дали две низове са анаграми, като регистърът на буквите не играе роля. Учитыват се само символите; интервали или пунктуационни знаци не се вземат предвид.

anagram(‘finder’, ‘Friend’) -> true
anagram(‘hello’, ‘bye’) -> false

Разглеждаме задачата

Важно е да се вземе предвид, че трябва да проверявате всяка буква в двата входни низa и тяхното количество в всеки от тях.

finder -> f: 1 friend -> f: 1
i: 1 r: 1
n: 1 i: 1
d: 1 e: 1
e: 1 n: 1
r: 1 d: 1

За съхранение на данните на анаграмата, е добре да се избере структура като обектен литерал на JavaScript. Ключът в този случай е символ на буквата, а стойността — количеството на нейните повторения в текущия низ.

Има и други условия:

  • Трябва да се уверим, че регистърът на буквите не се взема предвид при сравняването. Просто преобразуваме двата низа в малки или големи букви.
  • Изключваме от сравняването всички не-символи. Най-добре работи с регулярни изрази.

Решение

// helper function that builds the
// object to store the data
const buildCharObject = str => {
  const charObj = {}
  for(let char of str.replace(/[^w]/g).toLowerCase()) {
    // if the object has already a key value pair
    // equal to the value being looped over,
    // increase the value by 1, otherwise add
    // the letter being looped over as key and 1 as its value
    charObj[char] = charObj[char] + 1 || 1
  }
  return charObj
}
 
// main function
const anagram = (strA, strB) => {
  // build the object that holds strA data
  const aCharObject = buildCharObject(strA)
  // build the object that holds strB data
  const bCharObject = buildCharObject(strB)
 
  // compare number of keys in the two objects
  // (anagrams must have the same number of letters)
  if(Object.keys(aCharObject).length !== Object.keys(bCharObject).length) {
    return false
  }
  // if both objects have the same number of keys
  // we can be sure that at least both strings
  // have the same number of characters
  // now we can compare the two objects to see if both
  // have the same letters in the same amount
  for(let char in aCharObject) {
    if(aCharObject[char] !== bCharObject[char]) {
      return false
    }
  }
  // if both the above checks succeed,
  // you have an anagram: return true
  return true
}

Обърнете внимание на използването на Object.keys() в горния сниппет. Този метод връща масив, съдържащ имена или ключове в същия ред, в който се срещат в обекта. В този случай масивът ще изглежда така:

[‘f’, ‘i’, ‘n’, ‘d’, ‘e’, ‘r’]

По този начин получаваме свойствата на обекта, без да е необходимо да изпълняваме обемен цикъл. В задачата може да се използва този метод със свойството .length — за проверка дали и в двете низове има еднакъв брой символи — това е важна характеристика на анаграмите.

Търсене на гласни

Достатъчно проста задача, която често се среща на интервюта.

Постановка

Трябва да напишете функция, приемаща низ като аргумент и връщаща броя на гласните, съдържащи се в низа.
Гласни са «a», «e», «i», «o», «u».

Пример:

findVowels(‘hello’) // —> 2
findVowels(‘why’) // —> 0

Решение

Ето най-простия вариант:

const findVowels = str => {
  let count = 0
  const vowels = ['a', 'e', 'i', 'o', 'u']
  for(let char of str.toLowerCase()) {
    if(vowels.includes(char)) {
      count++
    }
  }
  return count
}

Важно е да се обърне внимание на използването на метода .includes(). Той е достъпен както за низове, така и за масиви. Следва да се прилага, за да се установи дали масивът съдържа определена стойност. Този метод връща true, ако масивът съдържа указаната стойност, и false, ако не съдържа.

Има и по-кратко решение на проблема:

const findVowels = str => {
  const matched = str.match(/[aeiou]/gi)
  return matched ? matched.length : 0
}

Тук се използва методът .match(), който позволява извършването на ефективно търсене. Ако регулярното изражение като аргумент на метода бъде намерено в указаната низа, то връщаното значение става масив от съвпадащи символи. А ако няма съвпадения, .match() връща null.

Фибоначи

Класическа задача, която може да се срещне на интервюта с най-различно ниво. Струва си да се припомни, че последователността на Фибоначи е редица числа, където всяко следващо е сумата на двете предишни. Така първите десет числа изглеждат по следния начин: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34.

Постановка

Трябва да напишете функция, която връща n-та стойност в определената последователност, като n е числото, което се предава като аргумент на функцията.

fibonacci(3) // —> 2

Тази задача включва циклично преминаване толкова пъти, колкото е посочено в аргумента, с връщане на стойността на съответната позиция. Този начин на формулиране на задачата изисква използването на цикли. Ако вместо това използвате рекурсия, това може да хареса на интервюиращия и да ви донесе няколко допълнителни точки.

Решение

const fibonacci = num => {
  // съхраняваме числата от Фибоначи, които ще генерираме
  // в масив и
  // инициализираме масива с първите две
  // числа от последователността
  const result = [0, 1]

  for(let i = 2; i <= num; i++) {
    // добавяме сумата на двете числа
    // предходни на позицията i в масива result
    // в края на масива result
    const prevNum1 = result[i - 1]
    const prevNum2 = result[i - 2]
    result.push(prevNum1 + prevNum2)
  }
  // връщаме последната стойност в масива result
  return result[num]
}

В масива с резултати първите две числа се съдържат в реда, тъй като всяко число от последователността е равно на сумата на двете предходни числа. В самото начало, обаче, няма две числа, които да вземем за получаване на следващото число, затова цикълът не може автоматично да ги генерира. Но, както знаем, първите две числа винаги са 0 и 1. Така че можем ръчно да инициализираме масива с резултати.

Що се отнася до рекурсията, тук всичко е по-просто и по-сложно едновременно:

const fibonacci = num => {
  // ако num е или 0 или 1, връщаме num
  if(num < 2) {
    return num
  }
  // рекурсия тук
  return fibonacci(num - 1) + fibonacci(num - 2)
}

Продължаваме да извикваме fibonacci(), предавайки все по-малки числа като аргументи. Спираме се, когато подаденият аргумент е 0 или 1.

Извод

Скоро вероятно вече сте се сблъсквали с някоя от тези задачи, ако сте преминали през интервюта за работа като frontend или JavaScript разработчик (особено на ниво junior). Но ако не сте ги срещали, те все пак могат да ви бъдат полезни в бъдеще — поне за общо развитие.

Skillbox препоръчва:

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster