5 tipuri de probleme întâlnite la interviuri pentru JavaScript: analize și soluții

5 tipuri de probleme întâlnite la interviuri pentru JavaScript: analize și soluții

Din partea traducătorului: am publicat pentru voi un articol Maria Perna, care povestește despre problemele tipice în JavaScript, cel mai adesea oferite candidaților dezvoltatori la interviuri. Articolul va fi util în primul rând pentru programatorii începători.

Interviurile în companiile tehnologice au devenit o poveste cunoscută. Nu este surprinzător — trecerea cu succes a interviului oferă oportunitatea de a obține un loc de muncă bun. Dar nu este atât de simplu, deoarece adesea este necesar să rezolvi probleme complexe.

Ceea ce este mai surprinzător, este că majoritatea acestor probleme nu au legătură cu munca pe care o va desfășura candidatul, dar totuși trebuie să fie rezolvate. Uneori, trebuie să faci acest lucru pe tablă, fără a verifica Google sau orice altă sursă. Da, situația se schimbă gradual și în unele companii renunță la aceste interviuri, dar mulți angajatori încă respectă această tradiție. Acest articol este dedicat analizării problemelor tipice de JavaScript care sunt frecvent utilizate ca exerciții pentru candidați.

Vă reamintim: pentru toți cititorii „Habr” — reducere de 10.000 de ruble la înscrierea la orice curs Skillbox cu codul de promovare „Habr”.

Skillbox recomandă: Curs practic «Dezvoltator mobil PRO».

Principalul — pregătirea temeinică pentru interviul tău

Da, înainte de a începe analiza problemelor, să discutăm despre sfaturile generale pentru pregătirea interviului.

Cel mai important — să te pregătești din timp. Verifică cât de bine îți amintești algoritmii și structurile de date și îmbunătățește ți cunoștințele în domeniile pe care nu le cunoști prea bine. Există multe platforme online care te pot ajuta să te pregătești pentru interviuri. Îți recomandăm GeeksforGeeks, Pramp, Interviewing.io și CodeSignal.

Este important să înveți să verbalizezi soluția tare. Este recomandat să le explici candidaților ce faci, nu doar să scrii pe tablă (sau să tastezi cod pe computer, de asemenea în tăcere). Astfel, dacă faci o eroare în cod, dar abordarea soluției este corectă în general, îți poți crește șansele de succes.

Trebuie să înțelegi problema înainte de a începe soluționarea. În unele cazuri, poți înțelege superficial sarcina și apoi să mergi pe o cale greșită. Poate că ar trebui să pui câteva întrebări de clarificare intervievatorului.

Trebuie să exersezi scrierea codului manual, nu pe PC. Uneori, în interviurile de angajare, candidatul primește un marker și o tablă, fără niciun indiciu sau formatare automată. Atunci când căutați soluții, ar trebui să scrieți codul pe o bucată de hârtie sau chiar pe tablă. Dacă țineți totul în minte, este posibil să uitați ceva important.

Sarcini tipice în JavaScript

Probabil că unele dintre aceste sarcini vă sunt deja cunoscute. Fie că ați parcurs interviuri în care a fost necesar să rezolvați ceva similar, fie că v-ați exersat cu ele în timpul studierii JavaScript. Acum a venit momentul să le rezolvați din nou, cu o explicație detaliată a procesului.

Palindrom

Palindromul este un cuvânt, o propoziție sau o secvență de caractere care se citește exact la fel, atât în direcția obișnuită, cât și înapoi. De exemplu, “Anna” este un palindrom, iar “table” și “John” nu sunt.

Formularea

Se dă un șir; trebuie să scrieți o funcție care returnează true dacă șirul este un palindrom și false în caz contrar. În acest caz, trebuie să ținem cont de spații și semne de punctuație.

palindrome(‘racecar’) === true
palindrome(‘table’) === false

Analizăm sarcina

Ideea principală aici este de a inversa șirul în direcția opusă. Dacă șirul „inversat” este complet identic cu cel original, atunci am obținut un palindrom și funcția ar trebui să returneze true. Dacă nu, returnează false.

Soluție

Iată codul care rezolvă palindromul.

const palindrome = str => {
  // transformă șirul în litere mici
  str = str.toLowerCase()
  // inversează șirul de intrare și returnează rezultatul
  // comparării
  return str === str.split('').reverse().join('')
}

Primul pas este transformarea caracterelor din șirul de intrare în litere mici. Aceasta asigură că programul va compara exact caracterele și nu cazul sau alte aspecte.

Al doilea pas este inversarea șirului. Acest lucru nu este dificil: trebuie să-l transformăm într-un array folosind metoda .split() (biblioteca String). Apoi inversăm array-ul, folosind .reverse() (biblioteca Array). Ultimul pas este conversia array-ului inversat într-un șir cu ajutorul .join() (biblioteca Array).

Acum tot ce trebuie să facem este să comparăm șirul „inversat” cu cel original, returnând rezultatul true sau false.

FizzBuzz

Una dintre cele mai populare sarcini în interviuri.

Formularea

Este necesar să scrieți o funcție care să afișeze în consolă numerele de la 1 la n, unde n este un număr întreg, pe care funcția îl primește ca parametru, cu următoarele condiții:

  • afișați fizz în locul numerelor care sunt multipli de 3;
  • afișarea buzz în loc de numerele care sunt multipli de 5;
  • afișarea fizzbuzz în loc de numerele care sunt multipli atât de 3, cât și de 5.

Exemplu

Fizzbuzz(5)

Rezultatul

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

Analizăm sarcina

Principalul aici este modul de a găsi numerele multiple folosind JavaScript. Acesta poate fi implementat cu ajutorul operatorului modulo sau rest, care arată restul împărțirii a două numere. Dacă restul este 0, aceasta înseamnă că primul număr este multiplu de al doilea.

12 % 5 // 2 -> 12 nu este un multiplu de 5
12 % 3 // 0 -> 12 este multiplu de 3

Așadar, dacă împărțim 12 la 5, obținem 2 cu rest 2. Dacă împărțim 12 la 3, obținem 4 cu rest 0. În primul caz, 12 nu este multiplu de 5, iar în al doilea, 12 este multiplu de 3.

Soluție

Soluția optimă va fi următorul cod:

const fizzBuzz = num => {
  for(let i = 1; i <= num; i++) {
    // verifică dacă numărul este multiplu de 3 și 5
    if(i % 3 === 0 && i % 5 === 0) {
      console.log('fizzbuzz')
    } // verifică dacă numărul este multiplu de 3
      else if(i % 3 === 0) {
      console.log('fizz')
    } // verifică dacă numărul este multiplu de 5
      else if(i % 5 === 0) {
      console.log('buzz')
    } else {
      console.log(i)
    }
  }
}

Funcția efectuează verificările necesare folosind operatori condiționali și returnează rezultatul dorit utilizatorului. În sarcină, este important să se acorde atenție ordinii operatorilor if…else: să înceapă cu condiția dublă (&&) și să se termine cu cazul în care nu au fost găsite numere multiple. Ca rezultat, acoperim toate variantele.

Anagramă

Aceasta este o denumire pentru un cuvânt care conține toate literele unui alt cuvânt în aceeași cantitate, dar într-o altă ordine.

Formularea

Trebuie să scrii o funcție care verifică dacă două șiruri sunt anagrame, fără a ține cont de capitalizare. Se iau în considerare doar caracterele; spațiile sau semnele de punctuație nu sunt incluse în calcul.

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

Analizăm sarcina

Aici este important să se verifice fiecare literă în cele două șiruri de intrare și numărul acestora în fiecare șir.

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

Pentru stocarea datelor anagramelor, este bine să alegi o structură precum un literal de obiect JavaScript. Cheia în acest caz este caracterul literei, iar valoarea este numărul de apariții în șirul curent.

Există și alte condiții:

  • Trebuie să ne asigurăm că capitalizarea literelor nu este luată în considerare la comparare. Pur și simplu transformăm ambele șiruri în litere mici sau mari.
  • Excludem din comparație toate non-caracterele. Cel mai bine este să lucrăm cu expresii regulate.

Soluție

// 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
}

Atenție la utilizarea Object.keys() în snippetul de mai sus. Această metodă returnează un array care conține numele sau cheile într-o ordine similară cu cea în care apar în obiect. În acest caz, array-ul va fi astfel:

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

Astfel, obținem proprietățile obiectului fără a fi nevoie să executăm un ciclu voluminos. În această sarcină, putem folosi această metodă cu proprietatea .length - pentru a verifica dacă ambele stringuri au același număr de caractere - aceasta fiind o caracteristică importantă a anagramelor.

Căutarea vocalelor

O sarcină destul de simplă, care apare frecvent la interviuri.

Formularea

Trebuie să scriem o funcție care primește un string ca argument și returnează numărul de vocale conținute în string.
Vocalele sunt „a”, „e”, „i”, „o”, „u”.

Exemplu:

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

Soluție

Iată cea mai simplă variantă:

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
}

Este important să ne concentrăm pe utilizarea metodei .includes(). Aceasta este disponibilă atât pentru stringuri, cât și pentru array-uri. Este recomandat să o aplicați pentru a identifica dacă un array conține o valoare specifică. Această metodă returnează true dacă array-ul conține valoarea specificată și false dacă nu.

Există și o soluție mai concisă la problemă:

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

Aici este utilizată metoda .match(), care permite realizarea unei căutări eficiente. Dacă expresia regulată ca argument al metodei este găsită în stringul specificat, valoarea returnată devine un array de caractere corespunzătoare. Dacă nu există corespondențe, .match() returnează null.

Fibonacci

O sarcină clasică pe care o poți întâlni la interviuri de diferite niveluri. Merită să reamintim că secvența Fibonacci este un șir de numere, unde fiecare număr următor este suma celor două anterioare. Astfel, primele zece numere sunt: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34.

Formularea

Trebuie să scriem o funcție care returnează n-a înregistrare dintr-o secvență specifică, unde n este un număr care este transmis ca argument al funcției.

fibonacci(3) // —> 2

Această sarcină implică parcurgerea unui ciclu de un număr de ori specificat în argument, cu returnarea valorii corespunzătoare de la acea poziție. Această abordare necesită utilizarea buclelor. Totuși, dacă folosești recursivitatea, acest lucru poate impresiona intervievatorul și îți poate aduce câteva puncte suplimentare.

Soluție

const fibonacci = num => {
  // stochează secvența Fibonacci pe care vrei să o generezi
  // într-un array și
  // inițializează array-ul cu primele două
  // numere ale secvenței
  const result = [0, 1]

  for(let i = 2; i <= num; i++) {
    // adaugă suma celor două numere
    // anterioare poziției i în array-ul rezultat
    // la finalul array-ului rezultat
    const prevNum1 = result[i - 1]
    const prevNum2 = result[i - 2]
    result.push(prevNum1 + prevNum2)
  }
  // returnează ultima valoare din array-ul rezultat
  return result[num]
}

În array-ul rezultat, primele două numere sunt conținute în rând, deoarece fiecare intrare din secvență este suma celor două numere anterioare. La început, nu există două numere din care să poți obține următorul număr, așa că bucla nu le poate genera automat. Dar, știm că primele două numere sunt întotdeauna 0 și 1. Așadar, se poate inițializa manual array-ul rezultat.

Cât despre recursivitate, aici lucrurile sunt mai simple și mai complicate în același timp:

const fibonacci = num => {
  // dacă num este fie 0, fie 1, returnează num
  if(num < 2) {
    return num
  }
  // recursivitate aici
  return fibonacci(num - 1) + fibonacci(num - 2)
}

Continui să apelăm fibonacci(), transmițând numere din ce în ce mai mici ca argumente. Ne oprim atunci când argumentul trecut este 0 sau 1.

Ieșire

Cel mai probabil, ai întâlnit deja una dintre sarcinile menționate, dacă ai participat la interviuri pentru dezvoltator frontend sau JavaScript (mai ales la nivel junior). Dar, dacă nu ți-au apărut, acestea îți pot fi utile în viitor — cel puțin pentru dezvoltarea personală.

Skillbox recomandă:

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster