Палиндром в JavaScript

Я пытаюсь написать код, чтобы определить, является ли строка палиндромом. Я делаю строку строчными буквами, вынимаю пробелы и превращаю ее в массив. Затем я делю его пополам, переворачиваю вторую половину и сравниваю эти два массива, чтобы увидеть, является ли строка палиндромом. Функция не регистрирует истину.

let string = "Never odd or even";
let lowerString = string.toLowerCase();
let split = lowerString.split("");
let array = split.filter(noSpaces);

function noSpaces(i) {
  return i !== " ";
}

function checkIfPal() {
  if (array.length % 2 === 1) {
    let firstHalf = array.slice(0, array.length / 2);
    let secondHalf = array.slice(array.length / 2 + 1, array.length);
    let revSecondHalf = [];
    for (let i = secondHalf.length - 1; i > -1; i--) {
      revSecondHalf.push(secondHalf[i]);
    }
    if (firstHalf === revSecondHalf) {
      console.log("true for odd");
    } else {
      console.log("false for odd");
    }
  } else {
    let firstHalf = array.slice(0, array.length / 2);
    let secondHalf = array.slice(array.length / 2, array.length);
    let revSecondHalf = [];
    for (let i = secondHalf.length - 1; i > -1; i--) {
      revSecondHalf.push(secondHalf[i]);
    }
    if (firstHalf === revSecondHalf) {
      console.log("true for even");
    } else {
      console.log("false for even");
    }
  }
}
checkIfPal();

person Keegan Sanders    schedule 22.11.2018    source источник
comment
Возможный дубликат строки проверки для палиндрома   -  person Akrion    schedule 22.11.2018
comment
Почему бы просто не проверить, совпадает ли символ в i с символом в length - i - 1, пока не дойдете до половины пути? Кроме того, Я не уверен, что не так не является достаточным объяснением вашей проблемы, что пошло не так?   -  person RobG    schedule 22.11.2018
comment
Вы пытаетесь сравнить два массива, используя ===, что у вас не получается. Вам нужно join объединить массивы в две строки и затем сравнить их.   -  person Andy    schedule 22.11.2018
comment
Однострочный для развлечения: const isPalindrome = s => s.length <= 1 ? true : (s.substr(-1) === s.substr(0, 1) && isPalindrome(s.substr(1, length-2))) Вы можете предварительно обработать строку, чтобы удалить пробелы и верхние буквы.   -  person spender    schedule 22.11.2018
comment
@ spender - все это можно сделать без рекурсии еще несколькими символами: let isPalindrome = s => s.toLowerCase().replace(/[^a-z0-9]/g,'').split('').every((c, i, o) => c == o[o.length - ++i]), хотя он выполняет примерно в два раза больше тестов, чем требуется минимально. :-)   -  person RobG    schedule 22.11.2018


Ответы (4)


Есть гораздо более простой способ сделать это.

  1. Удалите все, что не является буквой или цифрой
  2. Сделайте строку в нижнем регистре
  3. Оберните петлей половину струны
  4. Сравнить текущую букву с последней буквой минус текущая позиция

function isPalindrome(str) {
    str = str.replace(/[^\w\d]/g, '').toLowerCase();
    const len = str.length;

    for (let i = 0; i < len / 2; i++) {
        if (str[i] !== str[len - 1 - i]) {
            return false;
        }
    }

    return true;
}

console.log(isPalindrome('A man, a plan, a canal, Panama!'));
console.log(isPalindrome('Mr. Owl Ate My Metal Worm'));
console.log(isPalindrome('A Santa Lived As a Devil At NASA'));

И еще есть очень простой, но не очень эффективный способ сделать это на длинных струнах.

function isPalindrome(str) {
    str = str.replace(/[^\w\d]/g, '').toLowerCase();
    return str === str.split('').reverse().join('');
}

console.log(isPalindrome('A man, a plan, a canal, Panama!'));
console.log(isPalindrome('Mr. Owl Ate My Metal Worm'));
console.log(isPalindrome('A Santa Lived As a Devil At NASA'));

person AnonymousSB    schedule 22.11.2018

В этой строке

if (firstHalf === revSecondHalf) {

вы пытаетесь сравнить два массива, но JavaScript не позволяет вам сделать это с ===, поскольку это два разных объекта. Либо join каждый массив в строку, а затем сравнивайте их, либо перебирайте элементы в одном массиве, сравнивая их с элементами с тем же индексом в другом массиве.

Первый способ проще.

person Andy    schedule 22.11.2018

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

Если переменные в сравнении ссылаются на один и тот же объект массива, это вернет true. Но если они указывают на два разных объекта массива, даже если их содержимое одинаково, он всегда будет возвращать false.

Если вы хотите продолжить использование массивов для сравнения, вам нужно будет проверить, одинаковы ли все элементы массива.

function compareArrayElements(arr1, arr2) {
    if (arr1.length != arr2.length)
        return false;
    for (var i=0;i<arr1.length;i++) {
        if (arr1[i] != arr2[i])
            return false;
    }
    return true;
}

Теперь, когда у вас есть решение, вы можете работать над его оптимизацией и уменьшением количества циклов for.

person samthecodingman    schedule 22.11.2018

Алгоритм, основанный на сравнении массива с его реверсом:

const isPalindrome = (str) => {
  //Eliminate punctuation and spaces
  // Force lower case
  // Split
   let arr = str.toString().replace(/[^A-Za-z0-9_]/g, "").toLowerCase().split('');

  // Join into one word
  let joined = arr.join('');

  // Reverse adn join into one word
  let reverseJoined = arr.reverse().join('');

  //compare
  return joined == reverseJoined;
}

console.log(isPalindrome('Red rum, sir, is murder'));
console.log(isPalindrome(404));
console.log(isPalindrome('Red rum, sir'));
console.log(isPalindrome(500));

person Razvan Zamfir    schedule 16.09.2020