Проверка палиндрома в Javascript

У меня есть следующее:

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');

Что не так с моим кодом? Я хочу проверить, является ли слово палиндромом.

47 ответов

Решение

Может быть, я предложу, вероятно, лучшее решение:

function checkPalindrom(str) {
    return str == str.split('').reverse().join('');
}

В 25 раз быстрее стандартного ответа

function isPalindrome(s,i) {
 return (i=i||0)<0||i>=s.length>>1||s[i]==s[s.length-1-i]&&isPalindrome(s,++i);
}

использовать как:

isPalindrome('racecar');

как он сам определяет "я"

Скрипка: http://jsfiddle.net/namcx0yf/9/

Это примерно в 25 раз быстрее, чем стандартный ответ ниже.

function checkPalindrome(str) {
  return str == str.split('').reverse().join('');
}

Скрипка: http://jsfiddle.net/t0zfjfab/2/

Просмотр консоли для результатов производительности.

Хотя решение трудно читать и поддерживать, я бы рекомендовал понять его, чтобы продемонстрировать отсутствие ветвления с рекурсией и сдвигом битов, чтобы произвести впечатление на вашего следующего интервьюера.

объяснил

|| и && используются для потока управления, как "if", "else". Если что-то осталось от || это правда, он просто выходит с истиной. Если что-то неверно, осталось от || это должно продолжаться. Если что-то осталось от && ложно, оно выходит как ложное, если что-то осталось от && истина, оно должно продолжаться. Это считается "не ветвящимся", так как не нуждается в прерываниях if-else, а только что оценивается.

1. Использовал инициализатор, не требующий определения "i" в качестве аргумента. Присваивает "i" себе, если оно определено, в противном случае инициализируется равным 0. Всегда ложно, поэтому всегда выполняется условие ИЛИ.

(i = i || 0) < 0

2. Проверяет, пошел ли "i" на полпути, но пропускает проверку среднего нечетного символа. Бит со сдвигом здесь подобен делению на 2, но до деления младшего четного соседа на 2 результата. Если true, то предполагает палиндром, так как это уже сделано. Если false, оценивается следующее условие ИЛИ.

i >= s.length >> 1

3. Сравнивает начальный и конечный символы в соответствии с "i", чтобы в конечном итоге встретить соседей или соседей в среднем символе. Если ложь выходит и предполагает НЕ палиндром. Если true, продолжается до следующего условия AND.

s[i] == s[s.length-1-i]

4. Снова вызывает себя для рекурсии, передавая исходную строку как "s". Так как "i" определенно определен на этом этапе, он предварительно увеличивается для продолжения проверки позиции строки. Возвращает логическое значение, указывающее, является ли палиндром.

isPalindrome(s,++i)

НО...

Простой цикл for примерно в два раза быстрее, чем мой причудливый ответ ( он же принцип KISS)

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/

Логика здесь не совсем верна, вам нужно проверять каждую букву, чтобы определить, является ли слово палиндромом. В настоящее время вы печатаете несколько раз. Как насчет того, чтобы сделать что-то вроде:

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");
}

Который должен напечатать, что это действительно палиндром.

Первая проблема

= это назначить == это сравнить

Вторая проблема, ваша логика здесь неверна

palindrom.charAt(palindrom.length)-1

Вы вычитаете один из charAt, а не из длины.

Третья проблема, это все равно будет неправильно, так как вы не уменьшаете длину на i.

Это работает для меня

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);
}

Как гораздо более понятная рекурсивная функция: 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(''));

}

Кратчайший код (31 символ)(ES6):

p=s=>s==[...s].reverse().join``
p('racecar'); //true

Как минимум три вещи:

  • Вы пытаетесь проверить на равенство с =, который используется для настройки. Вам нужно проверить с == или же ===, (Возможно, последнее, если у вас нет причин для первого.)

  • Вы сообщаете о результатах после проверки каждого персонажа. Но вы не узнаете результаты, пока не проверите достаточно символов.

  • Вы дважды проверяете каждую пару символов, так как вам нужно только проверить, скажем, first === last и не также, если 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');

Почему я печатаю результат за пределами цикла? В противном случае для каждого совпадения в слове будет напечатано "есть или нет паллиндром" вместо проверки всего слова.

РЕДАКТИРОВАТЬ: Обновлено с изменениями и исправлениями, предложенными Basemm.

Самое важное, что нужно сделать при решении технического теста - не использовать ярлыки - они хотят увидеть, как вы мыслите алгоритмически! Не ваше использование методов.

Вот тот, который я придумал (через 45 минут после того, как я провалил тест). Есть пара оптимизаций, чтобы сделать все же. При написании любого алгоритма лучше всего предположить, false и изменить логику, если она хочет быть true,

isPalindrome() :

По сути, для выполнения этой задачи с O (N) (линейной) сложностью необходимо иметь 2 итератора, векторы которых указывают друг на друга. Это означает, что один итератор начинается с начала, а другой - с конца, каждый движется внутрь. Вы можете сделать так, чтобы итераторы проходили весь массив и использовали условие для break / return как только они встретятся посередине, но это может сэкономить некоторую работу, чтобы дать каждому итератору половину длины по умолчанию.

for циклы, кажется, заставляют использовать больше проверок, поэтому я использовал while петли - что мне менее удобно.

Вот код:

/**
 * 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);

Обратите внимание, что, если циклы отсчитываются, возвращается true, Вся логика должна быть инвертирована, чтобы она по умолчанию возвращала false, Я также использовал один метод сокращения String.prototype.charAt(n), но я чувствовал себя хорошо с этим, так как каждый язык изначально поддерживает этот метод.

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

Находит и от верхнего до нижнего регистра. Разбейте строку на массив, я не знаю, почему осталось несколько пробелов, но я хотел поймать и отдельные буквы.

Я добавил еще несколько функций к вышеперечисленным функциям, чтобы проверить строки вроде: "Иди повесить салями, я лазанья свинья".

function checkPalindrom(str) {
    var str = str.replace(/[^a-zA-Z0-9]+/gi, '').toLowerCase();
    return str == str.split('').reverse().join('');
}

Спасибо

Вы можете попробовать следующее

function checkPalindrom (str) {
      str = str.toLowerCase();
      return str == str.split('').reverse().join('');
    }

    if(checkPalindrom('Racecar')) {
        console.log('Palindrome');
    } else {
        console.log('Not Palindrome');
    }
  • = в palindrom[i] = palindrom.charAt(palindrom.length)-1 должно быть == или же ===
  • palindrom.charAt(palindrom.length)-1 должно быть palindrom.charAt(palindrom.length - i)

Некоторые из приведенных выше коротких ответов хороши, но их нелегко понять, я предлагаю еще один способ:

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 стартовая форма слева, j начинать справа, пока их индекс не будет действительным (i<j). Это также работает на любых языках

Еще одно решение с ES6

isPalin = str => [...str].every((c, i) => c === str[str.length-1-i]);

Поделиться моим быстрым вариантом, который также поддерживает пробелы

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

Мне интересно, почему никто не предложил это:

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());

Рекурсивный метод:

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);

Некоторые примечательные логики для проверки палиндрома

Фильтр alphaNumeric и нечувствительность к регистру

Alnum фильтрация

      str = text.toLowerCase().replace(/[^A-Za-z0-9]/g,''); 

фильтрация символов без слов

      str = text.toLowerCase().replace(/[\W_]/g,'');

Логика палиндрома

встроенные методы [короче]

      const isPalindrome = (str) => str === [...str].reverse().join('');

итерация всех символов [проще]

      const isPalindrome = (str) => {
    let rev = "";
    length = str.length;
    while(length--){
        rev += str[length];
    }
    return str === rev;
}

Подход с двумя указателями [производительность]

      const isPalindrome = (str) => {
    const length = str.length;
    const halfLength = Math.floor(length /2);
    for(let i=0;i<halfLength; i++){
        if(str[i] !== str[length-1-i]){
            return false;
        }
    }
    return true;
}

рекурсивный [красноречивый]

      const isPalindrome = (str) => {
const length = str.length;
    if (length <= 1){
        return true;
    } else if (str.charAt(0) !== str.slice(-1)){
        return false;
    } else{
        return isPalindrome(str.substring(1,length-1));
    } 
}

Для большего количества способов

Несколько способов проверить палиндромы

Странное решение для проверки ваших навыков

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');

Я думал, что поделюсь своим собственным решением:

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');

Надеюсь, кто-то поможет.

`
function checkPalindrome (str) {
    var str = str.toLowerCase();
    var original = str.split(' ').join('');
    var reversed = original.split(' ').reverse().join('');

  return (original === reversed);
}
`

Как насчет этого, используя простой флаг

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');

Вот решение, которое работает, даже если строка содержит не алфавитно-цифровые символы.

function isPalindrome(str) {
    str = str.toLowerCase().replace(/\W+|_/g, '');
    return str == str.split('').reverse().join('');
}

Я нашел это на сайте интервью:

Напишите эффективную функцию, которая проверяет, является ли любая перестановка входной строки палиндромом. Вы можете игнорировать знаки препинания, нам важны только символы.

Поиграв с этим я придумал этот уродливый кусок кода:)

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

Просто оставлю это здесь для потомков.

(JavaScript) Используя regexp, он проверяет буквенно-цифровой палиндром и игнорирует пробелы и знаки препинания.

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.

Это сработало для меня.

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");

Если вам нужна эффективность и простота, я рекомендую такой подход:

function Palindrome(str) {
    let len = str.length, 
        i = 0;

    if (len < 3) 
        return false;

    while (len--) {
        if (str[i] === str[len])
            i++;
        else
            return false;
    }

    return true;
}

console.log(Palindrome('aba'))//true
console.log(Palindrome('abc'))//false

Думаю, я поделюсь своим решением с помощью Array.prototype.filter(). filter() фильтрует массив на основе логических значений, возвращаемых функцией.

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);
Другие вопросы по тегам