Skip to content

Instantly share code, notes, and snippets.

@martin-mok
Last active July 29, 2023 17:04
Show Gist options
  • Select an option

  • Save martin-mok/c17cd95cd67c76aa93c1ae04a229ed29 to your computer and use it in GitHub Desktop.

Select an option

Save martin-mok/c17cd95cd67c76aa93c1ae04a229ed29 to your computer and use it in GitHub Desktop.
freecodecamp: Palindrome Checker

Description

Return true if the given string is a palindrome. Otherwise, return false. A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing. Note
You'll need to remove all non-alphanumeric characters (punctuation, spaces and symbols) and turn everything into the same case (lower or upper case) in order to check for palindromes. We'll pass strings with varying formats, such as "racecar", "RaceCar", and "race CAR" among others. We'll also pass strings with special symbols, such as "2A3*3a2", "2A3 3a2", and "2_A3*3#A2".

Tests

tests:
  - text: <code>palindrome("eye")</code> should return a boolean.
    testString: assert(typeof palindrome("eye") === "boolean");
  - text: <code>palindrome("eye")</code> should return true.
    testString: assert(palindrome("eye") === true);
  - text: <code>palindrome("_eye")</code> should return true.
    testString: assert(palindrome("_eye") === true);
  - text: <code>palindrome("race car")</code> should return true.
    testString: assert(palindrome("race car") === true);
  - text: <code>palindrome("not a palindrome")</code> should return false.
    testString: assert(palindrome("not a palindrome") === false);
  - text: <code>palindrome("A man, a plan, a canal. Panama")</code> should return true.
    testString: assert(palindrome("A man, a plan, a canal. Panama") === true);
  - text: <code>palindrome("never odd or even")</code> should return true.
    testString: assert(palindrome("never odd or even") === true);
  - text: <code>palindrome("nope")</code> should return false.
    testString: assert(palindrome("nope") === false);
  - text: <code>palindrome("almostomla")</code> should return false.
    testString: assert(palindrome("almostomla") === false);
  - text: <code>palindrome("My age is 0, 0 si ega ym.")</code> should return true.
    testString: assert(palindrome("My age is 0, 0 si ega ym.") === true);
  - text: <code>palindrome("1 eye for of 1 eye.")</code> should return false.
    testString: assert(palindrome("1 eye for of 1 eye.") === false);
  - text: '<code>palindrome("0_0 (: /-\ :) 0-0")</code> should return true.'
    testString: 'assert(palindrome("0_0 (: /-\ :) 0-0") === true);'
  - text: <code>palindrome("five|\_/|four")</code> should return false.
    testString: assert(palindrome("five|\_/|four") === false);

Solution

My soln:
function palindrome(str) {
  let newStr=str.slice().toLowerCase().replace(/[\W_]+/g,"");
  const ReverseString = s => [...s].reverse().join(''); 
  if(newStr===ReverseString(newStr)){
    return true;
  }
  return false;
}

palindrome("eye");

Somehow, it is the basic solution. The most inefficient one.
The simpler solutions perform very poorly on long strings because they operate on the whole string multiple times (toLowerCase(), replace(), split(), reverse(), join()) before comparing the whole string twice.

Soln 2:

function palindrome(str) {
  str = str.toLowerCase().replace(/[\W_]/g, "");
  for (var i = 0, len = str.length - 1; i < len / 2; i++) {
    if (str[i] !== str[len - i]) {
      return false;
    }
  }
  return true;
}

This soln uses for loop to check on both sides of the string moves closer to the center until we have checked all of the letters. However, it still need to preform the replace() on the whole string first.

Soln 3(The fastest way):

//this solution performs at minimum 7x better, at maximum infinitely better.
//read the explanation for the reason why.
function palindrome(str) {
  //assign a front and a back pointer
  let front = 0;
  let back = str.length - 1;

  //back and front pointers won't always meet in the middle, so use (back > front)
  while (back > front) {
    //increments front pointer if current character doesn't meet criteria
    if (str[front].match(/[\W_]/)) {
      front++;
      continue;
    }
    //decrements back pointer if current character doesn't meet criteria
    if (str[back].match(/[\W_]/)) {
      back--;
      continue;
    }
    //finally does the comparison on the current character
    if (str[front].toLowerCase() !== str[back].toLowerCase()) return false;
    front++;
    back--;
  }

  //if the whole string has been compared without returning false, it's a palindrome!
  return true;
}
  • The beauty of this solution is it never needs to read through the whole string, even once, to know that it’s not a palindrome. Why read through the whole string if you can tell that it’s not a palindrome just by looking at two letters?
  • Uses a while loop instead of a for loop as a best practice - because we are using two variables, one is the index starting from the beginning of the string, and the other starts at the end of the string.
  • See Cyclomatic complexity

References

stackoverflow

Replace all non Alpha Numeric characters, New Lines, and multiple White Space with one Space
Check string for palindrome

freecodecamp

Palindrome Checker freecodecamp guide
freeCodeCamp Challenge Guide: Palindrome Checker
Cyclomatic complexity wiki

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment