π₯ Kill this interview question π₯
π― The challenge
Write a function that β given a string β returns true if the string is a palindrome or false otherwise.
Let's look at 11 different approaches to solving this in JavaScript ππ§΅
π― The challenge
Write a function that β given a string β returns true if the string is a palindrome or false otherwise.
Let's look at 11 different approaches to solving this in JavaScript ππ§΅
π The definition
A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward, such as taco cat or madam or racecar or the number 10801.
- Wikipedia
A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward, such as taco cat or madam or racecar or the number 10801.
- Wikipedia
According to the definition, we need to strip potential non-alphanumeric characters thus convert to lower-case.
So in all of the following solutions, we will be using a "clean" function to get a clean sequence of characters.
So in all of the following solutions, we will be using a "clean" function to get a clean sequence of characters.
To measure the different approaches, I'm gonna run them all through palindromes of various lengths, and measure runtime performance in NodeJS.
- A small palindrome of 10 characters
- A medium palindrome of 1000 characters
- A large palindrome of 5000 characters
- A small palindrome of 10 characters
- A medium palindrome of 1000 characters
- A large palindrome of 5000 characters
Performance:
Small: 0.0731 ms
Medium: 0.1267 ms
Large: 0.6272 ms
Pros:
Performs very well, even on large strings.
We are able to return as soon as we identify the first violation.
Cons:
In the world of ES6, this solution appears a bit βclumsyβ to read.
Small: 0.0731 ms
Medium: 0.1267 ms
Large: 0.6272 ms
Pros:
Performs very well, even on large strings.
We are able to return as soon as we identify the first violation.
Cons:
In the world of ES6, this solution appears a bit βclumsyβ to read.
Performance:
Small: 0.0415 ms
Medium: 0.0966 ms
Large: 0.9997 ms
Pros:
Performs good, and looks fairly readable.
We are able to return as soon as we identify the first violation.
Cons:
We imperatively mutate the array, which cost us a bit of performance.
Small: 0.0415 ms
Medium: 0.0966 ms
Large: 0.9997 ms
Pros:
Performs good, and looks fairly readable.
We are able to return as soon as we identify the first violation.
Cons:
We imperatively mutate the array, which cost us a bit of performance.
Performance:
Small: 0.1633 ms
Medium: 0.1986 ms
Large: 1.5192 ms
Pros:
Concise and very readable.
Easy to understand what is going on.
Cons:
Not the most well-performing, namely on small strings.
Small: 0.1633 ms
Medium: 0.1986 ms
Large: 1.5192 ms
Pros:
Concise and very readable.
Easy to understand what is going on.
Cons:
Not the most well-performing, namely on small strings.
Performance:
Small: 0.0444 ms
Medium: 0.1487 ms
Large: 1.2537 ms
Pros:
Plus points for using ES6 methods.
Overall more readable and easy to understand.
Cons:
With forEach we cannot break the iteration, nor can we ensure only doing string.length / 2 total iterations.
Small: 0.0444 ms
Medium: 0.1487 ms
Large: 1.2537 ms
Pros:
Plus points for using ES6 methods.
Overall more readable and easy to understand.
Cons:
With forEach we cannot break the iteration, nor can we ensure only doing string.length / 2 total iterations.
Performance:
Small: 0.0644 ms
Medium: 0.1560 ms
Large: 0.9630 ms
Pros:
Plus points for using ES6 methods.
Cons:
With map we cannot break the iteration, nor can we ensure only doing string.length / 2 total iterations.
Small: 0.0644 ms
Medium: 0.1560 ms
Large: 0.9630 ms
Pros:
Plus points for using ES6 methods.
Cons:
With map we cannot break the iteration, nor can we ensure only doing string.length / 2 total iterations.
Performance:
Small: 0.0425 ms
Medium: 0.1830 ms
Large: 0.8459 ms
Pros:
Plus points for using ES6 methods.
Cons:
If the check fails early, we keep passing on false to the next iteration.
This may seem like quite a waste, namely on larger strings.
Small: 0.0425 ms
Medium: 0.1830 ms
Large: 0.8459 ms
Pros:
Plus points for using ES6 methods.
Cons:
If the check fails early, we keep passing on false to the next iteration.
This may seem like quite a waste, namely on larger strings.
Performance:
Small: 0.0414 ms
Medium: 0.1977 ms
Large: 1.4204 ms
Pros:
Concise.
Will break early if a character does not match.
Cons:
We canβt ensure only doing string.length / 2 total iterations.
In the case of a palindrome, every will iterate through the whole array.
Small: 0.0414 ms
Medium: 0.1977 ms
Large: 1.4204 ms
Pros:
Concise.
Will break early if a character does not match.
Cons:
We canβt ensure only doing string.length / 2 total iterations.
In the case of a palindrome, every will iterate through the whole array.
Performance:
Small: 0.0842 ms
Medium: 5.1806 ms
Large: 108.5716 ms
Pros:
The interviewer may give you credit for knowing how to handle recursion.
Other than that, there is probably not much good to say about this solution.
Small: 0.0842 ms
Medium: 5.1806 ms
Large: 108.5716 ms
Pros:
The interviewer may give you credit for knowing how to handle recursion.
Other than that, there is probably not much good to say about this solution.
Cons:
There are, on the other hand, some considerations here.
We are opening a lot of function closures, and building up a β potentially β large call stack.
Notice how the performance on the large string blows through the roof here, compared to any of the previous solutions.
There are, on the other hand, some considerations here.
We are opening a lot of function closures, and building up a β potentially β large call stack.
Notice how the performance on the large string blows through the roof here, compared to any of the previous solutions.
Result:
100.00%
80.95%
27.27%
0.00%
0.00%
Performance:
Small: 0.0718 ms
Medium: 0.2233 ms
Large: 1.4426 ms
100.00%
80.95%
27.27%
0.00%
0.00%
Performance:
Small: 0.0718 ms
Medium: 0.2233 ms
Large: 1.4426 ms
πΈ Using cosine similarity
The idea is, that we are going to split the string into two equal parts and then revert one of them.
Then we convert them into their vector representation in n dimensions, n being the length of the half strings.
The idea is, that we are going to split the string into two equal parts and then revert one of them.
Then we convert them into their vector representation in n dimensions, n being the length of the half strings.
Then we are going to measure the angle between these vectors.
The bigger the angle, the bigger the mismatch between the strings.
Sounds fun, right? π€©
Let's do this!! π
The bigger the angle, the bigger the mismatch between the strings.
Sounds fun, right? π€©
Let's do this!! π
The tricky part is to represent a character as a number that includes both the character itself and its position in the string.
Here, Iβm using the characters charCode and then subtracting the position in the array from that number.
Here, Iβm using the characters charCode and then subtracting the position in the array from that number.
Alright, assuming we've converted both strings into vector representations, we can now proceed with the following steps:
- Calculate the dot product of the two vectors
- Calculate the magnitude of each vector
- Calculate the cosine of the angle between the vectors
- Calculate the dot product of the two vectors
- Calculate the magnitude of each vector
- Calculate the cosine of the angle between the vectors
Result:
100.00%
90.04%
57.90%
69.17%
12.37%
Performance:
Small: 0.0314 ms
Medium: 0.2597 ms
Large: 1.5066 ms
100.00%
90.04%
57.90%
69.17%
12.37%
Performance:
Small: 0.0314 ms
Medium: 0.2597 ms
Large: 1.5066 ms
πΈ Using Levenshtein distance
Are you still here after all that? π
Haha - you're insane!
Keep reading, cause it's getting worse π
Are you still here after all that? π
Haha - you're insane!
Keep reading, cause it's getting worse π
Just as with the previous approach, we are going to start by splitting the string up into two half strings and revert the second one.
The idea is to calculate the Levenshtein distance between these two strings and convert that into a measure of percentage.
The idea is to calculate the Levenshtein distance between these two strings and convert that into a measure of percentage.
Letβs go through this setup, and see how we can use this to approximate a string in terms of a palindrome.
- Split the string into two even half strings
- Reverse the second half
- Create a matrix
- Fill the matrix
- Count edits
- Convert into percentage
- Split the string into two even half strings
- Reverse the second half
- Create a matrix
- Fill the matrix
- Count edits
- Convert into percentage
Result:
100.00%
80.00%
27.27%
6.67%
0.00%
Performance:
Small: 0.0635 ms
Medium: 32.5343 ms
Large: 616.9648 ms
100.00%
80.00%
27.27%
6.67%
0.00%
Performance:
Small: 0.0635 ms
Medium: 32.5343 ms
Large: 616.9648 ms
Are you kidding me?!
Did you really read all the way to here?
You are either extremely committed or totally crazy π
Did you really read all the way to here?
You are either extremely committed or totally crazy π
Loading suggestions...