Related
I have the following:
function checkPalindrom(palindrom)
{
for( var i = palindrom.length; i > 0; i-- )
{
if( palindrom[i] = palindrom.charAt(palindrom.length)-1 )
{
document.write('the word is palindrome.');
}else{
document.write('the word is not palindrome!');
}
}
}
checkPalindrom('wordthatwillbechecked');
What is wrong with my code? I want to check if the word is a palindrome.
Maybe I will suggest alternative solution:
function checkPalindrom (str) {
return str == str.split('').reverse().join('');
}
UPD. Keep in mind however that this is pretty much "cheating" approach, a demonstration of smart usage of language features, but not the most practical algorithm (time O(n), space O(n)). For real life application or coding interview you should definitely use loop solution. The one posted by Jason Sebring in this thread is both simple and efficient (time O(n), space O(1)).
25x faster than the standard answer
function isPalindrome(s,i) {
return (i=i||0)<0||i>=s.length>>1||s[i]==s[s.length-1-i]&&isPalindrome(s,++i);
}
use like:
isPalindrome('racecar');
as it defines "i" itself
Fiddle: http://jsfiddle.net/namcx0yf/9/
This is ~25 times faster than the standard answer below.
function checkPalindrome(str) {
return str == str.split('').reverse().join('');
}
Fiddle: http://jsfiddle.net/t0zfjfab/2/
View console for performance results.
Although the solution is difficult to read and maintain, I would recommend understanding it to demonstrate non-branching with recursion and bit shifting to impress your next interviewer.
explained
The || and && are used for control flow like "if" "else". If something left of || is true, it just exits with true. If something is false left of || it must continue. If something left of && is false, it exits as false, if something left of a && is true, it must continue. This is considered "non-branching" as it does not need if-else interupts, rather its just evaluated.
1. Used an initializer not requiring "i" to be defined as an argument. Assigns "i" to itself if defined, otherwise initialize to 0. Always is false so next OR condition is always evaluated.
(i = i || 0) < 0
2. Checks if "i" went half way but skips checking middle odd char. Bit shifted here is like division by 2 but to lowest even neighbor division by 2 result. If true then assumes palindrome since its already done. If false evaluates next OR condition.
i >= s.length >> 1
3. Compares from beginning char and end char according to "i" eventually to meet as neighbors or neighbor to middle char. If false exits and assumes NOT palindrome. If true continues on to next AND condition.
s[i] == s[s.length-1-i]
4. Calls itself again for recursion passing the original string as "s". Since "i" is defined for sure at this point, it is pre-incremented to continue checking the string's position. Returns boolean value indicating if palindrome.
isPalindrome(s,++i)
BUT...
A simple for loop is still about twice as fast as my fancy answer (aka KISS principle)
function fastestIsPalindrome(str) {
var len = Math.floor(str.length / 2);
for (var i = 0; i < len; i++)
if (str[i] !== str[str.length - i - 1])
return false;
return true;
}
http://jsfiddle.net/6L953awz/1/
The logic here is not quite correct, you need to check every letter to determine if the word is a palindrome. Currently, you print multiple times. What about doing something like:
function checkPalindrome(word) {
var l = word.length;
for (var i = 0; i < l / 2; i++) {
if (word.charAt(i) !== word.charAt(l - 1 - i)) {
return false;
}
}
return true;
}
if (checkPalindrome("1122332211")) {
document.write("The word is a palindrome");
} else {
document.write("The word is NOT a palindrome");
}
Which should print that it IS indeed a palindrome.
First problem
= is assign
== is compare
Second problem, Your logic here is wrong
palindrom.charAt(palindrom.length)-1
You are subtracting one from the charAt and not the length.
Third problem, it still will be wrong since you are not reducing the length by i.
It works to me
function palindrome(str) {
/* remove special characters, spaces and make lowercase*/
var removeChar = str.replace(/[^A-Z0-9]/ig, "").toLowerCase();
/* reverse removeChar for comparison*/
var checkPalindrome = removeChar.split('').reverse().join('');
/* Check to see if str is a Palindrome*/
return (removeChar === checkPalindrome);
}
As a much clearer recursive function: http://jsfiddle.net/dmz2x117/
function isPalindrome(letters) {
var characters = letters.split(''),
firstLetter = characters.shift(),
lastLetter = characters.pop();
if (firstLetter !== lastLetter) {
return false;
}
if (characters.length < 2) {
return true;
}
return isPalindrome(characters.join(''));
}
SHORTEST CODE (31 chars)(ES6):
p=s=>s==[...s].reverse().join``
p('racecar'); //true
Keep in mind short code isn't necessarily the best. Readability and efficiency can matter more.
At least three things:
You are trying to test for equality with =, which is used for setting. You need to test with == or ===. (Probably the latter, if you don't have a reason for the former.)
You are reporting results after checking each character. But you don't know the results until you've checked enough characters.
You double-check each character-pair, as you really only need to check if, say first === last and not also if last === first.
function checkPalindrom(palindrom)
{
var flag = true;
var j = 0;
for( var i = palindrom.length-1; i > palindrom.length / 2; i-- )
{
if( palindrom[i] != palindrom[j] )
{
flag = false;
break; // why this? It'll exit the loop at once when there is a mismatch.
}
j++;
}
if( flag ) {
document.write('the word is palindrome.');
}
else {
document.write('the word is not palindrome.');
}
}
checkPalindrom('wordthatwillbechecked');
Why am I printing the result outside the loop? Otherwise, for each match in the word, it'll print "is or is not pallindrome" rather than checking the whole word.
EDIT: Updated with changes and a fix suggested by Basemm.
I've added some more to the above functions, to check strings like, "Go hang a salami, I'm a lasagna hog".
function checkPalindrom(str) {
var str = str.replace(/[^a-zA-Z0-9]+/gi, '').toLowerCase();
return str == str.split('').reverse().join('');
}
Thanks
The most important thing to do when solving a Technical Test is Don't use shortcut methods -- they want to see how you think algorithmically! Not your use of methods.
Here is one that I came up with (45 minutes after I blew the test). There are a couple optimizations to make though. When writing any algorithm, its best to assume false and alter the logic if its looking to be true.
isPalindrome():
Basically, to make this run in O(N) (linear) complexity you want to have 2 iterators whose vectors point towards each other. Meaning, one iterator that starts at the beginning and one that starts at the end, each traveling inward. You could have the iterators traverse the whole array and use a condition to break/return once they meet in the middle, but it may save some work to only give each iterator a half-length by default.
for loops seem to force the use of more checks, so I used while loops - which I'm less comfortable with.
Here's the code:
/**
* TODO: If func counts out, let it return 0
* * Assume !isPalindrome (invert logic)
*/
function isPalindrome(S){
var s = S
, len = s.length
, mid = len/2;
, i = 0, j = len-1;
while(i<mid){
var l = s.charAt(i);
while(j>=mid){
var r = s.charAt(j);
if(l === r){
console.log('#while *', i, l, '...', j, r);
--j;
break;
}
console.log('#while !', i, l, '...', j, r);
return 0;
}
++i;
}
return 1;
}
var nooe = solution('neveroddoreven'); // even char length
var kayak = solution('kayak'); // odd char length
var kayaks = solution('kayaks');
console.log('#isPalindrome', nooe, kayak, kayaks);
Notice that if the loops count out, it returns true. All the logic should be inverted so that it by default returns false. I also used one short cut method String.prototype.charAt(n), but I felt OK with this as every language natively supports this method.
function palindromCheck(str) {
var palinArr, i,
palindrom = [],
palinArr = str.split(/[\s!.?,;:'"-()]/ig);
for (i = 0; i < palinArr.length; i++) {
if (palinArr[i].toLowerCase() === palinArr[i].split('').reverse().join('').toLowerCase() &&
palinArr[i] !== '') {
palindrom.push(palinArr[i]);
}
}
return palindrom.join(', ');
}
console.log(palindromCheck('There is a man, his name! was Bob.')); //a, Bob
Finds and upper to lower case. Split string into array, I don't know why a few white spaces remain, but I wanted to catch and single letters.
= in palindrom[i] = palindrom.charAt(palindrom.length)-1 should be == or ===
palindrom.charAt(palindrom.length)-1 should be palindrom.charAt(palindrom.length - i)
Sharing my fast variant which also support spaces
function isPalindrom(str) {
var ia = 0;
var ib = str.length - 1;
do {
if (str[ia] === str[ib]) continue;
// if spaces skip & retry
if (str[ia] === ' ' && ib++) continue;
if (str[ib] === ' ' && ia--) continue;
return false;
} while (++ia < --ib);
return true;
}
var palindrom="never odd or even";
var res = isPalindrom(palindrom);
document.getElementById('check').innerHTML ='"'+ palindrom + '"'+" checked to be :" +res;
<span id="check" />
Some above short anwsers is good, but it's not easy for understand, I suggest one more way:
function checkPalindrome(inputString) {
if(inputString.length == 1){
return true;
}else{
var i = 0;
var j = inputString.length -1;
while(i < j){
if(inputString[i] != inputString[j]){
return false;
}
i++;
j--;
}
}
return true;
}
I compare each character, i start form left, j start from right, until their index is not valid (i<j).
It's also working in any languages
One more solution with ES6
isPalin = str => [...str].every((c, i) => c === str[str.length-1-i]);
You can try the following
function checkPalindrom (str) {
str = str.toLowerCase();
return str == str.split('').reverse().join('');
}
if(checkPalindrom('Racecar')) {
console.log('Palindrome');
} else {
console.log('Not Palindrome');
}
function checkPalindrom(palindrom)
{
palindrom= palindrom.toLowerCase();
var flag = true;
var j;
j = (palindrom.length) -1 ;
//console.log(j);
var cnt = j / 2;
//console.log(cnt);
for( i = 0; i < cnt+1 ; i++,j-- )
{
console.log("J is => "+j);
console.log(palindrom[i] + "<==>" + palindrom[j]);
if( palindrom[i] != palindrom[j] )
{
flag = false;
break;
}
}
if( flag ) {
console.log('the word is palindrome.');
}
else {
console.log('the word is not palindrome.');
}
}
checkPalindrom('Avid diva');
I'm wondering why nobody suggested this:
ES6:
// "aba" -> true
// "acb" -> false
// "aa" -> true
// "abba" -> true
// "s" -> true
isPalindrom = (str = "") => {
if (str[0] === str[str.length - 1]) {
return str.length <= 1 ? true : isPalindrom(str.slice(1, -1))
}
return false;
}
alert(["aba", "acb", "aa", "abba", "s"].map((e, i) => isPalindrom(e)).join())
ES5:
// "aba" -> true
// "acb" -> false
// "aa" -> true
// "abba" -> true
// "s" -> true
function isPalindrom(str) => {
var str = typeof str !== "string" ? "" : str;
if (str[0] === str[str.length - 1]) {
return str.length <= 1 ? true : isPalindrom(str.slice(1, -1))
}
return false;
}
alert(["aba", "acb", "aa", "abba", "s"].map(function (e, i) {
return isPalindrom(e);
}).join());
Recursive Method:
var low;
var high;
var A = "abcdcba";
function palindrome(A , low, high){
A = A.split('');
if((low > high) || (low == high)){
return true;
}
if(A[low] === A[high]){
A = A.join('');
low = low + 1;
high = high - 1;
return palindrome(A , low, high);
}
else{
return "not a palindrome";
}
}
palindrome(A, 0, A.length-1);
I thought I'd share my own solution:
function palindrome(string){
var reverseString = '';
for(var k in string){
reverseString += string[(string.length - k) - 1];
}
if(string === reverseString){
console.log('Hey there palindrome');
}else{
console.log('You are not a palindrome');
}
}
palindrome('ana');
Hope will help someone.
I found this on an interview site:
Write an efficient function that checks whether any permutation of an
input string is a palindrome. You can ignore punctuation, we only care
about the characters.
Playing around with it I came up with this ugly piece of code :)
function checkIfPalindrome(text) {
var found = {};
var foundOne = 0;
text = text.replace(/[^a-z0-9]/gi, '').toLowerCase();
for (var i = 0; i < text.length; i++) {
if (found[text[i]]) {
found[text[i]]++;
} else {
found[text[i]] = 1;
}
}
for (var x in found) {
if (found[x] === 1) {
foundOne++;
if (foundOne > 1) {
return false;
}
}
}
for (var x in found) {
if (found[x] > 2 && found[x] % 2 && foundOne) {
return false;
}
}
return true;
}
Just leaving it here for posterity.
How about this, using a simple flag
function checkPalindrom(str){
var flag = true;
for( var i = 0; i <= str.length-1; i++){
if( str[i] !== str[str.length - i-1]){
flag = false;
}
}
if(flag == false){
console.log('the word is not a palindrome!');
}
else{
console.log('the word is a palindrome!');
}
}
checkPalindrom('abcdcba');
(JavaScript) Using regexp, this checks for alphanumeric palindrome and disregards space and punctuation.
function palindrome(str) {
str = str.match(/[A-Za-z0-9]/gi).join("").toLowerCase();
// (/[A-Za-z0-9]/gi) above makes str alphanumeric
for(var i = 0; i < Math.floor(str.length/2); i++) { //only need to run for half the string length
if(str.charAt(i) !== str.charAt(str.length-i-1)) { // uses !== to compare characters one-by-one from the beginning and end
return "Try again.";
}
}
return "Palindrome!";
}
palindrome("A man, a plan, a canal. Panama.");
//palindrome("4_2 (: /-\ :) 2-4"); // This solution would also work on something like this.
`
function checkPalindrome (str) {
var str = str.toLowerCase();
var original = str.split(' ').join('');
var reversed = original.split(' ').reverse().join('');
return (original === reversed);
}
`
This avoids regex while also dealing with strings that have spaces and uppercase...
function isPalindrome(str) {
str = str.split("");
var str2 = str.filter(function(x){
if(x !== ' ' && x !== ',') {
return x;
}
});
return console.log(str2.join('').toLowerCase()) == console.log(str2.reverse().join('').toLowerCase());
};
isPalindrome("A car, a man, a maraca"); //true
function myPolidrome(polidrome){
var string=polidrome.split('').join(',');
for(var i=0;i<string.length;i++){
if(string.length==1){
console.log("is polidrome");
}else if(string[i]!=string.charAt(string.length-1)){
console.log("is not polidrome");
break;
}else{
return myPolidrome(polidrome.substring(1,polidrome.length-1));
}
}
}
myPolidrome("asasdsdsa");
Thought I will share my solution using Array.prototype.filter(). filter()
filters the array based on boolean values the function returns.
var inputArray=["","a","ab","aba","abab","ababa"]
var outputArray=inputArray.filter(function isPalindrome(x){
if (x.length<2) return true;
var y=x.split("").reverse().join("");
return x==y;
})
console.log(outputArray);
This worked for me.
var number = 8008
number = number + "";
numberreverse = number.split("").reverse().join('');
console.log ("The number if reversed is: " +numberreverse);
if (number == numberreverse)
console.log("Yes, this is a palindrome");
else
console.log("Nope! It isnt a palindrome");
Here is a solution that works even if the string contains non-alphanumeric characters.
function isPalindrome(str) {
str = str.toLowerCase().replace(/\W+|_/g, '');
return str == str.split('').reverse().join('');
}
I'm writing a primality checker in in j/s and I was wondering why I'm getting true as a return for when I test 55... It seems to work fine for all the other cases I checked just not 55, can someone tell me where I went wrong?
var isPrime = function(num){
if (num === 2){
return true;
}
else if(num%2 === 0){
return false;
}
else{
var i = 2;
while(i<num){
if((num/i) % i === 0 ){
return false;
}
i++
}
return true;
}
};
Thanks in advance and apologies for the noobness!
if((num/i) % i === 0 ){
return false;
}
What is this case?
Shouldn't it be
if(num % i === 0 ){
return false;
}
Just as #Andrey pointed out, your if statement inside the while loop is not correct. For 55 at i=5 you should get false for 55 being prime, but 55/5 % 5 == 1 Also you could use just == instead of === for logical equals, since === checks if both values and type are equal, which is not necessary here.
Try this.
var isPrime = function isPrime(value) {
var i = 2;
for(i; i < value; i++) {
if(value % i === 0) {
return false;
}
}
return value > 1;
};
Even if your bug may be solved, I'd recommend to think about some other aspects to optimize your code:
Clarify your corner cases: In the beginning, check for n<2 -> return false. At least to math theory primes are defined as natural number larger then 1, so 1 is by definition not a prime like all the negative numbers. Your code won't handle negative numbers correctly.
You don't have to check all divisors up to n-1. You can obviously stop checking at n/2, but there are even proofs for tighter bounds which means you can stop checking already at √n if I'm right. To further optimize, you don't have to check even divisors >2.
else {
var i = 3;
while ( i < num/2 ) {
if( num % i == 0 ) {
return false;
}
i+=2;
}
return true;
}
See https://en.wikipedia.org/wiki/Primality_test for details about testing of primes.
P.S: I just wrote the code here in the text box, but it looks like it might work.
I need to multiply two numbers in JavaScript, but I need to do without using the multiplication operator "*". Is it possible?
function a(b,c){
return b*c;
} // note:need to do this without the "*" operator
Yes. Because multiplication is just addition done multiple times. Also have meaningful signatures for methods instead of using single alphabets.
function multiply(num, times){
// TODO what if times is zero
// TODO what if times is negative
var n = num;
for(var i = 1; i < times; i++)
num += n; // increments itself
return num;
}
a=(b,c)=>Math.round(b/(1/c))
You need to be able to handle negatives and zeros. Other above answers don't help here. There are different ways. One relatively messy way could be ifs:
function multiply(num1, num2) {
var sum = 0;
for (var i = 0; i < Math.abs(num2); i++) {
sum += num1;
}
if (num1 < 0 && num2 < 0) {
return Math.abs(sum);
} else if (num1 < 0 || num2 < 0 ) {
return -sum;
} else {
return sum;
}
}
There is another simpler mathematical approach. Let's do this in C++:
double mult(double a, double b) {
return exp(log(a) + log(b));
}
The log() function in C++ returns the natural logarithm (base-e logarithm) of the argument passed in the parameter. (arguments can be any numeric type)
The exp() function in C++ returns the exponential (Euler's number) e (or 2.71828) raised to the given argument.
When you simplify the above statement, you eventually end up with a * b, but still there is no * sign.
*You need make sure both a and b are positive, otherwise you will get nan :(
Here is a math trick
function multiply(num1, num2) {
return num1/(1/num2);
}
console.log(multiply(5,22))
I think this can be solved using recursion. Sorry for the improper indentations.
We are given 2 numbers to multiply and multiplying m with n simply means adding m, n times.
if n becomes 0, return 0. This is our base case.
else
return m + multi(m,n-1)
we are returning m every time, because we need to add m up to n times
In every call we are decreasing the n's value so as the n becomes 1, we'll call it for the last time.
function multi (int m, int n){
if(n === 0)
return 0;
return m + multi(m,n-1);
}
repeat() method of string can be used to find multiplication of two numbers.
var a = 3;
var b = 4;
var res = "1".repeat(a).repeat(b).length;
console.log(res)
log: 12
It is repeating c, a times=> 'ccc' and then whole string b times=> 'cccccccccccc', length of the final string will be a*b;
This is similar to loop approach.
This approach is limited to positive and integer numbers only.
function multiply(num1, num2) {
let num = 0;
// Check whether one or both nums are negative
let flag = false;
if(num1 < 0 && num2 < 0){
flag = true;
// Make both positive numbers
num1 = Math.abs(num1);
num2 = Math.abs(num2);
}else if(num1 < 0 || num2 < 0){
flag = false;
// Make the negative number positive & keep in num2
if(num1 < 0){
temp = num2;
num2 = Math.abs(num1);
num1 = temp;
}else{
num2 = Math.abs(num2);
}
}else{
flag = true;
}
let product = 0;
while(num < num2){
product += num1;
num += 1;
}
// Condition satisfy only when 1 num is negative
if(!flag){
return -product;
}
return product;
}
console.log(multiply(-2,-2));
function multiple(a, b) {
let sum = 0;
for (let i = 0; i < Math.abs(b); i++) {
sum += Math.abs(a);
}
if (a < 0 && b < 0) {
return Math.abs(sum);
} else if (a < 0 || b < 0 ) {
return -sum;
} else {
return sum;
}
}
Is this from some programming puzzle or interview question? :)
Since multiplication is repeated addition, you probably want a loop which adds one of the factors to the result for each count in the other factor.
Have the function DashInsert(num) insert dashes ('-') between each two odd numbers in num. For example: if num is 454793 the output should be 4547-9-3. Don't count zero as an odd number.
Here is my code (not working). When I run it, I get the same response as an infinite loop where I have to kill the page but I can't see why. I know there are ways to do this by keeping it as a string but now I'm wondering why my way isn't working. Thanks...
function DashInsert(num) {
num = num.split("");
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
num.splice(i, 0, "-");
}
}
num = num.join("");
return num;
}
Using num.splice you are inserting new entries into the array, therefor increasing its length – and that makes the value of i “running behind” the increasing length of the array, so the break condition is never met.
And apart from that, on the next iteration after inserting a -, num[i-1] will be that - character, and therefor you are practically trying to check if '-' % 2 != 0 … that makes little sense as well.
So, when you insert a - into the array, you have to increase i by one as well – that will a) account for the length of the array having increased by one, and also it will check the next digit after the - on the next iteration:
function DashInsert(num) {
num = num.split("");
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
num.splice(i, 0, "-");
i++; // <- this is the IMPORTANT part!
}
}
num = num.join("");
return num;
}
alert(DashInsert("454793"));
http://jsfiddle.net/37wA9/
Once you insert a dash -, the if statement is checking this '-'%2 != 0 which is always true and thus inserts another dash, ad infinitum.
Here's one way to do it with replace using a regex and function:
function DashInsert(n) {
var f = function(m,i,s) { return m&s[i+1]&1 ? m+'-' : m; };
return String(n).replace(/\d/g,f);
}
DashInsert(454793) // "4547-9-3"
When you are adding a dash, this dash will be processed as a number on the next iteration. You need to forward one step.
function DashInsert(num) {
var num = num.split("");
for (var i = 1; i < num.length; i++) {
if ((num[i - 1] % 2 != 0) && (num[i] % 2 != 0)) {
num.splice(i, 0, "-");
i++; // This is the only thing that needs changing
}
}
num = num.join("");
return num;
}
It's because there are cases when you use the % operator on dash '-' itself, e.g. right after you splice a dash into the array.
You can correct this behavior by using a clone array.
function DashInsert(num) {
num = num.split("");
var clone = num.slice(0);
var offset = 0;
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
clone.splice(i + offset, 0, "-");
offset++;
}
}
return clone.join("");
}
alert(DashInsert("45739"));
Output: 45-7-3-9
Demo: http://jsfiddle.net/262Bf/
To complement the great answers already given, I would like to share an alternative implementation, that doesn't modify arrays in-place:
function DashInsert(num) {
var characters = num.split("");
var numbers = characters.map(function(chr) {
return parseInt(chr, 10);
});
var withDashes = numbers.reduce(function(result, current) {
var lastNumber = result[result.length - 1];
if(lastNumber == null || current % 2 === 0 || lastNumber % 2 === 0) {
return result.concat(current);
} else {
return result.concat("-", current);
}
}, []);
return withDashes.join("");
}
It's longer, but IMHO reveals the intention better, and avoids the original issue.
I have the following:
function checkPalindrom(palindrom)
{
for( var i = palindrom.length; i > 0; i-- )
{
if( palindrom[i] = palindrom.charAt(palindrom.length)-1 )
{
document.write('the word is palindrome.');
}else{
document.write('the word is not palindrome!');
}
}
}
checkPalindrom('wordthatwillbechecked');
What is wrong with my code? I want to check if the word is a palindrome.
Maybe I will suggest alternative solution:
function checkPalindrom (str) {
return str == str.split('').reverse().join('');
}
UPD. Keep in mind however that this is pretty much "cheating" approach, a demonstration of smart usage of language features, but not the most practical algorithm (time O(n), space O(n)). For real life application or coding interview you should definitely use loop solution. The one posted by Jason Sebring in this thread is both simple and efficient (time O(n), space O(1)).
25x faster than the standard answer
function isPalindrome(s,i) {
return (i=i||0)<0||i>=s.length>>1||s[i]==s[s.length-1-i]&&isPalindrome(s,++i);
}
use like:
isPalindrome('racecar');
as it defines "i" itself
Fiddle: http://jsfiddle.net/namcx0yf/9/
This is ~25 times faster than the standard answer below.
function checkPalindrome(str) {
return str == str.split('').reverse().join('');
}
Fiddle: http://jsfiddle.net/t0zfjfab/2/
View console for performance results.
Although the solution is difficult to read and maintain, I would recommend understanding it to demonstrate non-branching with recursion and bit shifting to impress your next interviewer.
explained
The || and && are used for control flow like "if" "else". If something left of || is true, it just exits with true. If something is false left of || it must continue. If something left of && is false, it exits as false, if something left of a && is true, it must continue. This is considered "non-branching" as it does not need if-else interupts, rather its just evaluated.
1. Used an initializer not requiring "i" to be defined as an argument. Assigns "i" to itself if defined, otherwise initialize to 0. Always is false so next OR condition is always evaluated.
(i = i || 0) < 0
2. Checks if "i" went half way but skips checking middle odd char. Bit shifted here is like division by 2 but to lowest even neighbor division by 2 result. If true then assumes palindrome since its already done. If false evaluates next OR condition.
i >= s.length >> 1
3. Compares from beginning char and end char according to "i" eventually to meet as neighbors or neighbor to middle char. If false exits and assumes NOT palindrome. If true continues on to next AND condition.
s[i] == s[s.length-1-i]
4. Calls itself again for recursion passing the original string as "s". Since "i" is defined for sure at this point, it is pre-incremented to continue checking the string's position. Returns boolean value indicating if palindrome.
isPalindrome(s,++i)
BUT...
A simple for loop is still about twice as fast as my fancy answer (aka KISS principle)
function fastestIsPalindrome(str) {
var len = Math.floor(str.length / 2);
for (var i = 0; i < len; i++)
if (str[i] !== str[str.length - i - 1])
return false;
return true;
}
http://jsfiddle.net/6L953awz/1/
The logic here is not quite correct, you need to check every letter to determine if the word is a palindrome. Currently, you print multiple times. What about doing something like:
function checkPalindrome(word) {
var l = word.length;
for (var i = 0; i < l / 2; i++) {
if (word.charAt(i) !== word.charAt(l - 1 - i)) {
return false;
}
}
return true;
}
if (checkPalindrome("1122332211")) {
document.write("The word is a palindrome");
} else {
document.write("The word is NOT a palindrome");
}
Which should print that it IS indeed a palindrome.
First problem
= is assign
== is compare
Second problem, Your logic here is wrong
palindrom.charAt(palindrom.length)-1
You are subtracting one from the charAt and not the length.
Third problem, it still will be wrong since you are not reducing the length by i.
It works to me
function palindrome(str) {
/* remove special characters, spaces and make lowercase*/
var removeChar = str.replace(/[^A-Z0-9]/ig, "").toLowerCase();
/* reverse removeChar for comparison*/
var checkPalindrome = removeChar.split('').reverse().join('');
/* Check to see if str is a Palindrome*/
return (removeChar === checkPalindrome);
}
As a much clearer recursive function: http://jsfiddle.net/dmz2x117/
function isPalindrome(letters) {
var characters = letters.split(''),
firstLetter = characters.shift(),
lastLetter = characters.pop();
if (firstLetter !== lastLetter) {
return false;
}
if (characters.length < 2) {
return true;
}
return isPalindrome(characters.join(''));
}
SHORTEST CODE (31 chars)(ES6):
p=s=>s==[...s].reverse().join``
p('racecar'); //true
Keep in mind short code isn't necessarily the best. Readability and efficiency can matter more.
At least three things:
You are trying to test for equality with =, which is used for setting. You need to test with == or ===. (Probably the latter, if you don't have a reason for the former.)
You are reporting results after checking each character. But you don't know the results until you've checked enough characters.
You double-check each character-pair, as you really only need to check if, say first === last and not also if last === first.
function checkPalindrom(palindrom)
{
var flag = true;
var j = 0;
for( var i = palindrom.length-1; i > palindrom.length / 2; i-- )
{
if( palindrom[i] != palindrom[j] )
{
flag = false;
break; // why this? It'll exit the loop at once when there is a mismatch.
}
j++;
}
if( flag ) {
document.write('the word is palindrome.');
}
else {
document.write('the word is not palindrome.');
}
}
checkPalindrom('wordthatwillbechecked');
Why am I printing the result outside the loop? Otherwise, for each match in the word, it'll print "is or is not pallindrome" rather than checking the whole word.
EDIT: Updated with changes and a fix suggested by Basemm.
I've added some more to the above functions, to check strings like, "Go hang a salami, I'm a lasagna hog".
function checkPalindrom(str) {
var str = str.replace(/[^a-zA-Z0-9]+/gi, '').toLowerCase();
return str == str.split('').reverse().join('');
}
Thanks
The most important thing to do when solving a Technical Test is Don't use shortcut methods -- they want to see how you think algorithmically! Not your use of methods.
Here is one that I came up with (45 minutes after I blew the test). There are a couple optimizations to make though. When writing any algorithm, its best to assume false and alter the logic if its looking to be true.
isPalindrome():
Basically, to make this run in O(N) (linear) complexity you want to have 2 iterators whose vectors point towards each other. Meaning, one iterator that starts at the beginning and one that starts at the end, each traveling inward. You could have the iterators traverse the whole array and use a condition to break/return once they meet in the middle, but it may save some work to only give each iterator a half-length by default.
for loops seem to force the use of more checks, so I used while loops - which I'm less comfortable with.
Here's the code:
/**
* TODO: If func counts out, let it return 0
* * Assume !isPalindrome (invert logic)
*/
function isPalindrome(S){
var s = S
, len = s.length
, mid = len/2;
, i = 0, j = len-1;
while(i<mid){
var l = s.charAt(i);
while(j>=mid){
var r = s.charAt(j);
if(l === r){
console.log('#while *', i, l, '...', j, r);
--j;
break;
}
console.log('#while !', i, l, '...', j, r);
return 0;
}
++i;
}
return 1;
}
var nooe = solution('neveroddoreven'); // even char length
var kayak = solution('kayak'); // odd char length
var kayaks = solution('kayaks');
console.log('#isPalindrome', nooe, kayak, kayaks);
Notice that if the loops count out, it returns true. All the logic should be inverted so that it by default returns false. I also used one short cut method String.prototype.charAt(n), but I felt OK with this as every language natively supports this method.
function palindromCheck(str) {
var palinArr, i,
palindrom = [],
palinArr = str.split(/[\s!.?,;:'"-()]/ig);
for (i = 0; i < palinArr.length; i++) {
if (palinArr[i].toLowerCase() === palinArr[i].split('').reverse().join('').toLowerCase() &&
palinArr[i] !== '') {
palindrom.push(palinArr[i]);
}
}
return palindrom.join(', ');
}
console.log(palindromCheck('There is a man, his name! was Bob.')); //a, Bob
Finds and upper to lower case. Split string into array, I don't know why a few white spaces remain, but I wanted to catch and single letters.
= in palindrom[i] = palindrom.charAt(palindrom.length)-1 should be == or ===
palindrom.charAt(palindrom.length)-1 should be palindrom.charAt(palindrom.length - i)
Sharing my fast variant which also support spaces
function isPalindrom(str) {
var ia = 0;
var ib = str.length - 1;
do {
if (str[ia] === str[ib]) continue;
// if spaces skip & retry
if (str[ia] === ' ' && ib++) continue;
if (str[ib] === ' ' && ia--) continue;
return false;
} while (++ia < --ib);
return true;
}
var palindrom="never odd or even";
var res = isPalindrom(palindrom);
document.getElementById('check').innerHTML ='"'+ palindrom + '"'+" checked to be :" +res;
<span id="check" />
Some above short anwsers is good, but it's not easy for understand, I suggest one more way:
function checkPalindrome(inputString) {
if(inputString.length == 1){
return true;
}else{
var i = 0;
var j = inputString.length -1;
while(i < j){
if(inputString[i] != inputString[j]){
return false;
}
i++;
j--;
}
}
return true;
}
I compare each character, i start form left, j start from right, until their index is not valid (i<j).
It's also working in any languages
One more solution with ES6
isPalin = str => [...str].every((c, i) => c === str[str.length-1-i]);
You can try the following
function checkPalindrom (str) {
str = str.toLowerCase();
return str == str.split('').reverse().join('');
}
if(checkPalindrom('Racecar')) {
console.log('Palindrome');
} else {
console.log('Not Palindrome');
}
function checkPalindrom(palindrom)
{
palindrom= palindrom.toLowerCase();
var flag = true;
var j;
j = (palindrom.length) -1 ;
//console.log(j);
var cnt = j / 2;
//console.log(cnt);
for( i = 0; i < cnt+1 ; i++,j-- )
{
console.log("J is => "+j);
console.log(palindrom[i] + "<==>" + palindrom[j]);
if( palindrom[i] != palindrom[j] )
{
flag = false;
break;
}
}
if( flag ) {
console.log('the word is palindrome.');
}
else {
console.log('the word is not palindrome.');
}
}
checkPalindrom('Avid diva');
I'm wondering why nobody suggested this:
ES6:
// "aba" -> true
// "acb" -> false
// "aa" -> true
// "abba" -> true
// "s" -> true
isPalindrom = (str = "") => {
if (str[0] === str[str.length - 1]) {
return str.length <= 1 ? true : isPalindrom(str.slice(1, -1))
}
return false;
}
alert(["aba", "acb", "aa", "abba", "s"].map((e, i) => isPalindrom(e)).join())
ES5:
// "aba" -> true
// "acb" -> false
// "aa" -> true
// "abba" -> true
// "s" -> true
function isPalindrom(str) => {
var str = typeof str !== "string" ? "" : str;
if (str[0] === str[str.length - 1]) {
return str.length <= 1 ? true : isPalindrom(str.slice(1, -1))
}
return false;
}
alert(["aba", "acb", "aa", "abba", "s"].map(function (e, i) {
return isPalindrom(e);
}).join());
Recursive Method:
var low;
var high;
var A = "abcdcba";
function palindrome(A , low, high){
A = A.split('');
if((low > high) || (low == high)){
return true;
}
if(A[low] === A[high]){
A = A.join('');
low = low + 1;
high = high - 1;
return palindrome(A , low, high);
}
else{
return "not a palindrome";
}
}
palindrome(A, 0, A.length-1);
I thought I'd share my own solution:
function palindrome(string){
var reverseString = '';
for(var k in string){
reverseString += string[(string.length - k) - 1];
}
if(string === reverseString){
console.log('Hey there palindrome');
}else{
console.log('You are not a palindrome');
}
}
palindrome('ana');
Hope will help someone.
I found this on an interview site:
Write an efficient function that checks whether any permutation of an
input string is a palindrome. You can ignore punctuation, we only care
about the characters.
Playing around with it I came up with this ugly piece of code :)
function checkIfPalindrome(text) {
var found = {};
var foundOne = 0;
text = text.replace(/[^a-z0-9]/gi, '').toLowerCase();
for (var i = 0; i < text.length; i++) {
if (found[text[i]]) {
found[text[i]]++;
} else {
found[text[i]] = 1;
}
}
for (var x in found) {
if (found[x] === 1) {
foundOne++;
if (foundOne > 1) {
return false;
}
}
}
for (var x in found) {
if (found[x] > 2 && found[x] % 2 && foundOne) {
return false;
}
}
return true;
}
Just leaving it here for posterity.
How about this, using a simple flag
function checkPalindrom(str){
var flag = true;
for( var i = 0; i <= str.length-1; i++){
if( str[i] !== str[str.length - i-1]){
flag = false;
}
}
if(flag == false){
console.log('the word is not a palindrome!');
}
else{
console.log('the word is a palindrome!');
}
}
checkPalindrom('abcdcba');
(JavaScript) Using regexp, this checks for alphanumeric palindrome and disregards space and punctuation.
function palindrome(str) {
str = str.match(/[A-Za-z0-9]/gi).join("").toLowerCase();
// (/[A-Za-z0-9]/gi) above makes str alphanumeric
for(var i = 0; i < Math.floor(str.length/2); i++) { //only need to run for half the string length
if(str.charAt(i) !== str.charAt(str.length-i-1)) { // uses !== to compare characters one-by-one from the beginning and end
return "Try again.";
}
}
return "Palindrome!";
}
palindrome("A man, a plan, a canal. Panama.");
//palindrome("4_2 (: /-\ :) 2-4"); // This solution would also work on something like this.
`
function checkPalindrome (str) {
var str = str.toLowerCase();
var original = str.split(' ').join('');
var reversed = original.split(' ').reverse().join('');
return (original === reversed);
}
`
This avoids regex while also dealing with strings that have spaces and uppercase...
function isPalindrome(str) {
str = str.split("");
var str2 = str.filter(function(x){
if(x !== ' ' && x !== ',') {
return x;
}
});
return console.log(str2.join('').toLowerCase()) == console.log(str2.reverse().join('').toLowerCase());
};
isPalindrome("A car, a man, a maraca"); //true
function myPolidrome(polidrome){
var string=polidrome.split('').join(',');
for(var i=0;i<string.length;i++){
if(string.length==1){
console.log("is polidrome");
}else if(string[i]!=string.charAt(string.length-1)){
console.log("is not polidrome");
break;
}else{
return myPolidrome(polidrome.substring(1,polidrome.length-1));
}
}
}
myPolidrome("asasdsdsa");
Thought I will share my solution using Array.prototype.filter(). filter()
filters the array based on boolean values the function returns.
var inputArray=["","a","ab","aba","abab","ababa"]
var outputArray=inputArray.filter(function isPalindrome(x){
if (x.length<2) return true;
var y=x.split("").reverse().join("");
return x==y;
})
console.log(outputArray);
This worked for me.
var number = 8008
number = number + "";
numberreverse = number.split("").reverse().join('');
console.log ("The number if reversed is: " +numberreverse);
if (number == numberreverse)
console.log("Yes, this is a palindrome");
else
console.log("Nope! It isnt a palindrome");
Here is a solution that works even if the string contains non-alphanumeric characters.
function isPalindrome(str) {
str = str.toLowerCase().replace(/\W+|_/g, '');
return str == str.split('').reverse().join('');
}