Определить, является ли слово палиндромом

Палиндром — это слово, фраза или число, которое читается одинаково слева направо и справа налево. Например, слово "шалаш" или фраза "А роза упала на лапу Азора".

Дана функция: isPalindrom(str), которая аргументом принимает строку - слово и на выходе возвращает булевое значение, обозначающее, является ли слово палиндромом или нет. true- палиндром, false- не палиндром.

Примеры:

isPalindrom("казак") --> true,
isPalindrom("строка") --> false,
isPalindrom("шалаш") --> true,
isPalindrom("Ротор") --> true,
isPalindrom("Письмо") --> false,

Теория

Палиндром — это строка, которая читается одинаково слева направо и справа налево. На практике в задачах по Web-разработке почти всегда требуется дополнительно определить “правила сравнения”: учитывать ли регистр, пробелы, дефисы, букву ё и т.д.

Приведение к единому виду (нормализация входа)

Чтобы пример isPalindrom("Ротор") --> true работал, сравнение должно выполняться без учёта регистра: "Ротор" и "ротор" должны стать одинаковыми. Для этого выполняется преобразование в нижний регистр через toLowerCase().

Иногда требуется Unicode-нормализация: один и тот же видимый символ может быть представлен по-разному (как один кодовый пункт или как последовательность “базовый символ + комбинируемый знак”). Метод normalize() приводит строку к выбранной нормальной форме; практичным вариантом часто является "NFC", так как он приводит к канонической композиции.

Если входом строго является “слово” на кириллице без диакритики и экзотических символов, то normalize("NFC") обычно не влияет на результат, но остаётся безопасной “страховкой” на будущее.

Сравнение симметричных позиций

У палиндрома всегда выполняется условие: символ на позиции i равен символу на позиции len - 1 - i.
Из этого следует две полезные идеи:

  • достаточно проверить только первую половину строки;
  • при первом несовпадении можно сразу вернуть false (ранний выход), не продолжая вычисления.

Наглядная схема индексов для строки длины 5:

индексы:  0   1   2   3   4
символы:  a   b   c   b   a
пары:    (0,4) (1,3) центр=2

Для чётной длины, например 6:

индексы:  0   1   2   3   4   5
символы:  a   b   c   c   b   a
пары:    (0,5) (1,4) (2,3)

Время и память (простыми словами)

Если строка длины n, то в вариантах B и C выполняется примерно n/2 сравнений, но по принятой оценке сложности это O(n), потому что рост линейный. Память в этих вариантах O(1), так как не создаётся строка-«копия наоборот», сравнение происходит “на месте” по индексам.

Вариант A также имеет линейное время, но дополнительно создаёт структуру для разворота (split → массив, затем reverse, затем join), поэтому расход памяти выше.

Разбор крайних случаев

Ниже перечислены ситуации, которые часто встречаются в реальном коде и помогают сделать функцию надёжнее.

  • Не строковый ввод: преобразование через String(str) позволяет избежать ошибок при значениях вроде 123, null, undefined и всегда вернуть булево значение.
  • Пустая строка и строка из 1 символа: формально являются палиндромами, потому что читаются одинаково в обе стороны; при необходимости можно отдельно ввести правило “длина должна быть больше 1”.
  • Пробелы и знаки препинания: в данной формулировке задача про “слово”, поэтому фильтрация не требуется; для “фразового палиндрома” обычно добавляется удаление не-буквенно-цифровых символов и только затем выполняется сравнение.
  • Локаль и регистр: toLocaleLowerCase() может зависеть от локали, поэтому для предсказуемого результата чаще берётся toLowerCase().

При необходимости реализации “палиндрома-фразы” может быть добавлен отдельный этап “очистки” строки (пример показан как дополнительный материал):

function isPalindromPhrase(str) {
  const s = String(str)
    .normalize("NFC")
    .toLowerCase()
    .replace(/[^0-9a-zа-яё]/gi, "");

  let left = 0;
  let right = s.length - 1;

  while (left < right) {
    if (s[left] !== s[right]) return false;
    left++;
    right--;
  }

  return true;
}
Регулярное выражение для “очистки” зависит от требований: какие алфавиты поддерживаются, нужно ли сохранять ё, что делать с дефисом и т.д.; универсального варианта без уточнения правил не существует.

Кратко: палиндром определяется сравнением симметричных символов s[i] и s[len - 1 - i], причём достаточно пройти до середины строки. Для примера с "Ротор" требуется приведение к одному регистру, а для большей устойчивости к Unicode-особенностям полезно добавить normalize("NFC"); самым практичным считается подход “два указателя” с O(n) по времени и O(1) по памяти.