JavaScript: 20 Interview Programs with Solutions · Lesson 1 of 4

Lesson 1: Programs 1-5: Strings and Numbers

Reverse a string, check a palindrome, FizzBuzz, test for a prime number and compute a factorial in JavaScript, with tested solutions.

Lesson 1: Programs 1-5: Strings and Numbers

How to use this lesson. Read the question and try it yourself for ten minutes before you read the approach. In a real interview, say your idea out loud, mention the edge cases (empty input, one item, duplicates, negative numbers), then code, then test with an example.

Problem 1: Reverse a String

Question. Write a function that returns a string reversed.

Examples.

  • "Kathmandu" → "udnamhtaK"
  • "" → ""

Approach. Strings are unchangeable and have no reverse method. Turn the string into an array of characters, reverse it and join. Use the spread operator [...s] rather than split(""), because it keeps emoji and other multi-part characters intact. The manual version uses two pointers on an array.

function reverseString(s) {
  return [...s].reverse().join("");
}

function reverseTwoPointers(s) {
  const chars = [...s];
  let left = 0, right = chars.length - 1;
  while (left < right) {
    [chars[left], chars[right]] = [chars[right], chars[left]];
    left++;
    right--;
  }
  return chars.join("");
}

for (const text of ["Kathmandu", "", "a", "ab", "😀ab"]) {
  console.log(JSON.stringify(reverseString(text)), JSON.stringify(reverseTwoPointers(text)));
}

Output:

"udnamhtaK" "udnamhtaK"
"" ""
"a" "a"
"ba" "ba"
"ba😀" "ba😀"

Complexity. Both run in O(n) time and use O(n) extra space.

Follow-up an interviewer may ask. How would you reverse the words in a sentence but not the letters? (s.split(" ").reverse().join(" ").)

Problem 2: Check for a Palindrome

Question. Return true if a string reads the same forwards and backwards, ignoring case, spaces and punctuation.

Examples.

  • "A man, a plan, a canal: Panama" → true
  • "race a car" → false

Approach. Keep only letters and digits in lower case (a regular expression removes everything else), then compare from both ends with two pointers, stopping at the first difference.

function isPalindrome(s) {
  const chars = s.toLowerCase().replace(/[^a-z0-9]/g, "");
  let left = 0, right = chars.length - 1;
  while (left < right) {
    if (chars[left] !== chars[right]) return false;
    left++;
    right--;
  }
  return true;
}

for (const text of ["A man, a plan, a canal: Panama", "race a car", "", "a", "No lemon, no melon", "ab"]) {
  console.log(JSON.stringify(text), isPalindrome(text));
}

Output:

"A man, a plan, a canal: Panama" true
"race a car" false
"" true
"a" true
"No lemon, no melon" true
"ab" false

Complexity. O(n) time, O(n) space for the cleaned string. O(1) extra space is possible by moving two indexes past non-alphanumeric characters.

Follow-up an interviewer may ask. Can you do it without creating a new string? (Skip non-alphanumeric characters with the two indexes.)

Problem 3: FizzBuzz

Question. For the numbers 1 to n: print "Fizz" for multiples of 3, "Buzz" for multiples of 5, "FizzBuzz" for multiples of both, otherwise the number.

Examples.

  • n = 15 → 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz

Approach. Build the word from two parts so the both-multiples case is automatic. The classic mistake is testing 3 and 5 before 15, which prints only "Fizz".

function fizzbuzz(n) {
  const result = [];
  for (let i = 1; i <= n; i++) {
    let word = "";
    if (i % 3 === 0) word += "Fizz";
    if (i % 5 === 0) word += "Buzz";
    result.push(word || String(i));
  }
  return result;
}

console.log(fizzbuzz(15).join(", "));
console.log(fizzbuzz(0), fizzbuzz(1));

Output:

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz
[] [ '1' ]

Complexity. O(n) time and O(n) space for the result array.

Follow-up an interviewer may ask. How would you add a third rule, such as "Bazz" for multiples of 7? (The word-building version just gains one more if.)

Problem 4: Check for a Prime Number

Question. Return true if a number is prime (greater than 1 and divisible only by 1 and itself).

Examples.

  • 7 → true
  • 1 → false
  • 91 → false (7 x 13)

Approach. Numbers below 2 are not prime. Otherwise try dividing by 2, then only odd numbers up to the square root: a number with a factor larger than its square root also has a smaller one, so you never need to look further.

function isPrime(n) {
  if (!Number.isInteger(n) || n < 2) return false;
  if (n % 2 === 0) return n === 2;
  for (let d = 3; d * d <= n; d += 2) {
    if (n % d === 0) return false;
  }
  return true;
}

console.log(Array.from({ length: 32 }, (_, i) => i - 2).filter(isPrime));
console.log(isPrime(91), isPrime(97), isPrime(1000000007), isPrime(2.5));

Output:

[
   2,  3,  5,  7, 11,
  13, 17, 19, 23, 29
]
false true true false

Complexity. O(sqrt(n)) time, O(1) space.

Follow-up an interviewer may ask. How would you list all the primes up to a million? (The Sieve of Eratosthenes: O(n log log n).)

Problem 5: Factorial

Question. Compute n! = n x (n-1) x ... x 1, where 0! = 1. Reject negative numbers.

Examples.

  • 5 → 120
  • 0 → 1

Approach. A loop that multiplies is simplest and cannot overflow the call stack. The recursive version, n * factorial(n - 1), shows you understand recursion, but very deep recursion throws a stack error. Numbers above 170! overflow normal JavaScript numbers to Infinity; use BigInt for exact big results.

function factorial(n) {
  if (n < 0) throw new RangeError("factorial is not defined for negative numbers");
  let result = 1;
  for (let i = 2; i <= n; i++) result *= i;
  return result;
}

const factorialRecursive = (n) => (n <= 1 ? 1 : n * factorialRecursive(n - 1));

function factorialBig(n) {
  let result = 1n;
  for (let i = 2n; i <= BigInt(n); i++) result *= i;
  return result;
}

console.log([0, 1, 2, 3, 4, 5, 6, 7].map(factorial));
console.log(factorial(20), factorialRecursive(10));
console.log(factorial(171), factorialBig(25));
try { factorial(-1); } catch (e) { console.log(e.name + ":", e.message); }

Output:

[
   1,   1,   2,    6,
  24, 120, 720, 5040
]
2432902008176640000 3628800
Infinity 15511210043330985984000000n
RangeError: factorial is not defined for negative numbers

Complexity. O(n) time, O(1) space for the loop and O(n) stack for recursion.

Follow-up an interviewer may ask. How would you count the trailing zeros of n! without computing it? (Count the factors of 5: Math.floor(n/5) + Math.floor(n/25) + ....)

Finished this lesson?Log in to save your progress and pick up where you left off.
Next lesson →

Comments

Loading comments…

MeroSir Team
A free MeroSir course. Run the examples yourself and try the exercises: you learn programming by doing. Spotted a mistake? Use the Report button above the lesson.
Lesson 1: Programs 1-5: Strings and Numbers | MeroSir