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

Определение:

Палиндром - это слово, фраза, число или другая последовательность единиц, которая обладает свойством считывать одно и то же в любом направлении

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

Это был один из FAIQ [Часто задаваемый вопрос интервью] некоторое время назад, но в основном с использованием C.

Ищете решения на любых языках.

Ответ 1

Пример PHP:

$string = "A man, a plan, a canal, Panama";

function is_palindrome($string)
{
    $a = strtolower(preg_replace("/[^A-Za-z0-9]/","",$string));
    return $a==strrev($a);
}

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

Ответ 2

Windows XP (может также работать на 2000) или позже BATCH script:

@echo off

call :is_palindrome %1
if %ERRORLEVEL% == 0 (
    echo %1 is a palindrome
) else (
    echo %1 is NOT a palindrome
)
exit /B 0

:is_palindrome
    set word=%~1
    set reverse=
    call :reverse_chars "%word%"
    set return=1
    if "$%word%" == "$%reverse%" (
        set return=0
    )
exit /B %return%

:reverse_chars
    set chars=%~1
    set reverse=%chars:~0,1%%reverse%
    set chars=%chars:~1%
    if "$%chars%" == "$" (
        exit /B 0
    ) else (
        call :reverse_chars "%chars%"
    )
exit /B 0

Ответ 3

Язык агностический мета-код, затем...

rev = StringReverse(originalString)
return ( rev == originalString );

Ответ 4

С# алгоритм на месте. Любая предварительная обработка, например, нечувствительность к регистру или удаление пробелов и пунктуации, должны выполняться до перехода к этой функции.

boolean IsPalindrome(string s) {
    for (int i = 0; i < s.Length / 2; i++)
    {
        if (s[i] != s[s.Length - 1 - i]) return false;
    }
    return true;
}

Изменить: удалил ненужный "+1" в условиях цикла и потратил сохраненное сравнение на удаление избыточного сравнения длины. Спасибо комментаторам!

Ответ 5

С#: LINQ

var str = "a b a";
var test = Enumerable.SequenceEqual(str.ToCharArray(), 
           str.ToCharArray().Reverse());

Ответ 6

Более рубиновая переписывание версии Hal Ruby:

class String
  def palindrome?
    (test = gsub(/[^A-Za-z]/, '').downcase) == test.reverse
  end
end

Теперь вы можете вызвать palindrome? для любой строки.

Ответ 7

Неоптимизированный Python:

>>> def is_palindrome(s):
...     return s == s[::-1]

Ответ 8

Решение Java:

public class QuickTest {

public static void main(String[] args) {
    check("AmanaplanacanalPanama".toLowerCase());
    check("Hello World".toLowerCase());
}

public static void check(String aString) {
    System.out.print(aString + ": ");
    char[] chars = aString.toCharArray();
    for (int i = 0, j = (chars.length - 1); i < (chars.length / 2); i++, j--) {
        if (chars[i] != chars[j]) {
            System.out.println("Not a palindrome!");
            return;
        }
    }
    System.out.println("Found a palindrome!");
}

}

Ответ 9

Использование хорошей структуры данных обычно помогает произвести впечатление на профессора:

Нажмите половину символов на стек (длина/2).
Поп и сравните каждую char до первой разблокировки.
Если стек имеет нулевые элементы: палиндром.
* в случае строки с нечетной длиной, выкиньте средний char.

Ответ 10

C в доме. (не уверен, что вы не хотели здесь C)

bool IsPalindrome(char *s)
{
    int  i,d;
    int  length = strlen(s);
    char cf, cb;

    for(i=0, d=length-1 ; i < length && d >= 0 ; i++ , d--)
    {
        while(cf= toupper(s[i]), (cf < 'A' || cf >'Z') && i < length-1)i++;
        while(cb= toupper(s[d]), (cb < 'A' || cb >'Z') && d > 0       )d--;
        if(cf != cb && cf >= 'A' && cf <= 'Z' && cb >= 'A' && cb <='Z')
            return false;
    }
    return true;
}

Это вернет истину для "гоночного автомобиля", "гоночного автомобиля", "гоночного автомобиля", "гоночного автомобиля" и "RaCe cAr". Было бы легко изменить, чтобы включить символы или пробелы, но я считаю, что более полезно считать только буквы (и игнорировать регистр). Это работает для всех палиндромов, которые я нашел в ответах здесь, и я не смог обмануть его в ложные негативы/положительные результаты.

Кроме того, если вам не нравится bool в программе "C", он может, очевидно, возвращать int с возвратом 1 и возвращать 0 для true и false соответственно.

Ответ 11

Вот путь python. Примечание: на самом деле это не "pythonic", но демонстрирует алгоритм.

def IsPalindromeString(n):
    myLen = len(n)
    i = 0
    while i <= myLen/2:
        if n[i] != n[myLen-1-i]:
            return False
        i += 1
    return True

Ответ 12

Delphi

function IsPalindrome(const s: string): boolean;
var
  i, j: integer;
begin
  Result := false;
  j := Length(s);
  for i := 1 to Length(s) div 2 do begin
    if s[i] <> s[j] then
      Exit;
    Dec(j);
  end;
  Result := true;
end;

Ответ 13

ИЗМЕНИТЬ: из комментариев:

bool palindrome(std::string const& s) 
{ 
  return std::equal(s.begin(), s.end(), s.rbegin()); 
} 

Путь С++.

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

#include <string>
#include <iostream>

using namespace std;
bool palindrome(string foo)
{
    string::iterator front;
    string::reverse_iterator back;
    bool is_palindrome = true;
    for(front = foo.begin(), back = foo.rbegin();
        is_palindrome && front!= foo.end() && back != foo.rend();
        ++front, ++back
        )
    {
        if(*front != *back)
            is_palindrome = false;
    }
    return is_palindrome;
}
int main()
{
    string a = "hi there", b = "laval";

    cout << "String a: \"" << a << "\" is " << ((palindrome(a))? "" : "not ") << "a palindrome." <<endl;
    cout << "String b: \"" << b << "\" is " << ((palindrome(b))? "" : "not ") << "a palindrome." <<endl;

}

Ответ 14

Я вижу здесь много неправильных ответов. Любое правильное решение должно игнорировать пробелы и пунктуации (и любые неалфавитные символы на самом деле) и должно быть нечувствительным к регистру.

Несколько примеров хорошего примера:

"Человек, план, канал, Панама".

"Тойота Toyota".

"А"

""

Как и некоторые непалиндромы.

Пример решения в С# (примечание: пустые и нулевые строки считаются палиндромами в этой конструкции, если это нежелательно, легко изменить):

public static bool IsPalindrome(string palindromeCandidate)
{
    if (string.IsNullOrEmpty(palindromeCandidate))
    {
        return true;
    }
    Regex nonAlphaChars = new Regex("[^a-z0-9]");
    string alphaOnlyCandidate = nonAlphaChars.Replace(palindromeCandidate.ToLower(), "");
    if (string.IsNullOrEmpty(alphaOnlyCandidate))
    {
        return true;
    }
    int leftIndex = 0;
    int rightIndex = alphaOnlyCandidate.Length - 1;
    while (rightIndex > leftIndex)
    {
        if (alphaOnlyCandidate[leftIndex] != alphaOnlyCandidate[rightIndex])
        {
            return false;
        }
        leftIndex++;
        rightIndex--;
    }
    return true;
}

Ответ 15

boolean isPalindrome(String str1) {
  //first strip out punctuation and spaces
  String stripped = str1.replaceAll("[^a-zA-Z0-9]", "");
  return stripped.equalsIgnoreCase((new StringBuilder(stripped)).reverse().toString());
}

Версия Java

Ответ 16

Здесь мое решение в С#

static bool isPalindrome(string s)
{
    string allowedChars = "abcdefghijklmnopqrstuvwxyz"+
        "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    string compareString = String.Empty;
    string rev = string.Empty;

    for (int i = 0; i <= s.Length - 1; i++)
    {
        char c = s[i];

        if (allowedChars.IndexOf(c) > -1)
        {
            compareString += c;
        }
    }


    for (int i = compareString.Length - 1; i >= 0; i--)
    {
        char c = compareString[i];
        rev += c;
    }

    return rev.Equals(compareString, 
        StringComparison.CurrentCultureIgnoreCase);
}

Ответ 17

Здесь мое решение, не используя strrev. Написан на С#, но он будет работать на любом языке, который имеет функцию длины строки.

private static bool Pal(string s) {
    for (int i = 0; i < s.Length; i++) {
        if (s[i] != s[s.Length - 1 - i]) {
            return false;
        }
    }
    return true;
}

Ответ 18

Здесь находится версия Python, которая имеет дело с разными случаями, пунктуацией и пробелами.

import string

def is_palindrome(palindrome):
    letters = palindrome.translate(string.maketrans("",""),
                  string.whitespace + string.punctuation).lower()
    return letters == letters[::-1]

Изменить: Бесстыдно украл из оперный ответ Блэра Конрада, чтобы удалить немного неуклюжий список из моей предыдущей версии.

Ответ 19

Три версии в Smalltalk, от тупого до правильного.


В Smalltalk = - оператор сравнения:

isPalindrome: aString
    "Dumbest."
    ^ aString reverse = aString

Сообщение #translateToLowercase возвращает строку как строчную:

isPalindrome: aString
    "Case insensitive"
    |lowercase|
    lowercase := aString translateToLowercase.
    ^ lowercase reverse = lowercase

И в Smalltalk строки являются частью структуры Collection, вы можете использовать сообщение #select:thenCollect:, поэтому здесь последняя версия:

isPalindrome: aString
    "Case insensitive and keeping only alphabetic chars
    (blanks & punctuation insensitive)."
    |lowercaseLetters|
    lowercaseLetters := aString
        select: [:char | char isAlphabetic]
        thenCollect: [:char | char asLowercase]. 
    ^ lowercaseLetters reverse = lowercaseLetters

Ответ 20

Обфускация версии C:

int IsPalindrome (char *s)
{
  char*a,*b,c=0;
  for(a=b=s;a<=b;c=(c?c==1?c=(*a&~32)-65>25u?*++a,1:2:c==2?(*--b&~32)-65<26u?3:2:c==3?(*b-65&~32)-(*a-65&~32)?*(b=s=0,a),4:*++a,1:0:*++b?0:1));
  return s!=0;
}

Ответ 21

С++

std::string a = "god";
std::string b = "lol";

std::cout << (std::string(a.rbegin(), a.rend()) == a) << " " 
          << (std::string(b.rbegin(), b.rend()) == b);

Bash

function ispalin { [ "$( echo -n $1 | tac -rs . )" = "$1" ]; }
echo "$(ispalin god && echo yes || echo no), $(ispalin lol && echo yes || echo no)"

Gnu Awk

/* obvious solution */
function ispalin(cand, i) { 
    for(i=0; i<length(cand)/2; i++) 
        if(substr(cand, length(cand)-i, 1) != substr(cand, i+1, 1)) 
            return 0; 
    return 1; 
}

/* not so obvious solution. cough cough */
{ 
    orig = $0;
    while($0) { 
        stuff = stuff gensub(/^.*(.)$/, "\\1", 1); 
        $0 = gensub(/^(.*).$/, "\\1", 1); 
    }
    print (stuff == orig); 
}

Haskell

Какой-то мозг мертв, делая это в Haskell

ispalin :: [Char] -> Bool
ispalin a = a == (let xi (y:my) = (xi my) ++ [y]; xi [] = [] in \x -> xi x) a

Обычный английский

"Just reverse the string and if it is the same as before, it a palindrome"

Ответ 22

Ruby:

class String
    def is_palindrome?
        letters_only = gsub(/\W/,'').downcase
        letters_only == letters_only.reverse
    end
end

puts 'abc'.is_palindrome? # => false
puts 'aba'.is_palindrome? # => true
puts "Madam, I'm Adam.".is_palindrome? # => true

Ответ 23

Этот Java-код должен работать внутри метода boolean:

Примечание. Вам нужно только проверить первую половину символов с обратной половиной, иначе вы перекрываете и удваиваете количество проверок, которые необходимо выполнить.

private static boolean doPal(String test) {
    for(int i = 0; i < test.length() / 2; i++) {
        if(test.charAt(i) != test.charAt(test.length() - 1 - i)) {
            return false;
        }
    }
    return true;
}

Ответ 24

Другой С++. Оптимизирован для скорости и размера.

bool is_palindrome(const std::string& candidate) {
    for(std::string::const_iterator left = candidate.begin(), right = candidate.end(); left < --right ; ++left)
        if (*left != *right)
            return false;
    return true;
}

Ответ 25

Lisp:

(defun palindrome(x) (string= x (reverse x)))

Ответ 26

Обратите внимание, что в приведенных выше С++-решениях были некоторые проблемы.

Одно из решений было неэффективным, поскольку оно передало std::string по копиям, и потому что оно повторялось по всем символам, вместо сравнения только половины символов. Тогда даже при обнаружении строки не был палиндром, он продолжал цикл, ожидая своего конца, прежде чем сообщать "false".

Другой был лучше, с очень маленькой функцией, проблема которой заключалась в том, что он не смог проверить ничего, кроме std::string. В С++ легко распространить алгоритм на целую кучу похожих объектов. Шаблозируя свой std::string на "T", он работал бы как на std::string, std:: wstring, std::vector, так и на std:: deque. Но без существенных изменений из-за использования оператора <, std:: list был вне его области.

Мои собственные решения пытаются показать, что решение С++ не остановится при работе с токовым текущим типом, но будет стремиться работать над тем, что ведет себя одинаково, независимо от типа. Например, я мог бы применить мои тесты палиндрома в std::string, в векторе int или в списке "Anything", если Anything был сопоставим через свой оператор = (строить как типы, так и классы).

Обратите внимание, что шаблон можно даже расширить с помощью необязательного типа, который можно использовать для сравнения данных. Например, если вы хотите сравнить нечувствительным к регистру образом или даже сравнить аналогичные символы (например, è, é, ë, ê и e).

Как и царь Леонидас сказал бы: "Шаблоны? Это С++!!!"

Итак, в С++ существует по крайней мере 3 основных способа сделать это, каждый из которых ведет к другому:

Решение A: c-подобным образом

Проблема в том, что до С++ 0X мы не можем рассматривать массив символов std::string как смежный, поэтому мы должны "обмануть" и получить свойство c_str(). Поскольку мы используем его только для чтения, это должно быть нормально...


bool isPalindromeA(const std::string & p_strText)
{
   if(p_strText.length() < 2) return true ;
   const char * pStart = p_strText.c_str() ;             
   const char * pEnd = pStart + p_strText.length() - 1 ; 

   for(; pStart < pEnd; ++pStart, --pEnd)
   {
      if(*pStart != *pEnd)
      {
         return false ;
      }
   }

   return true ;
}

Решение B: более "С++" версия

Теперь мы попытаемся применить одно и то же решение, но к любому контейнеру С++ со случайным доступом к его элементам через operator []. Например, любые std:: basic_string, std::vector, std:: deque и т.д. Оператор [] является постоянным доступом для этих контейнеров, поэтому мы не будем терять чрезмерную скорость.


template <typename T>
bool isPalindromeB(const T & p_aText)
{
   if(p_aText.empty()) return true ;
   typename T::size_type iStart = 0 ;
   typename T::size_type iEnd = p_aText.size() - 1 ;

   for(; iStart < iEnd; ++iStart, --iEnd)
   {
      if(p_aText[iStart] != p_aText[iEnd])
      {
         return false ;
      }
   }

   return true ;
}

Решение C: Template powah!

Он будет работать практически с любым неупорядоченным STL-подобным контейнером с двунаправленными итераторами Например, любые std:: basic_string, std::vector, std:: deque, std:: list и т.д. Таким образом, эта функция может применяться ко всем STL-подобным контейнерам со следующими условиями: 1 - T - контейнер с двунаправленным итератором 2 - T указывает на сопоставимый тип (через оператор =)


template <typename T>
bool isPalindromeC(const T & p_aText)
{
   if(p_aText.empty()) return true ;
   typename T::const_iterator pStart = p_aText.begin() ;
   typename T::const_iterator pEnd = p_aText.end() ;
   --pEnd ;

   while(true)
   {
      if(*pStart != *pEnd)
      {
         return false ;
      }

      if((pStart == pEnd) || (++pStart == pEnd))
      {
         return true ;
      }

      --pEnd ;
   }
}

Ответ 27

Простое решение Java:

public boolean isPalindrome(String testString) {
    StringBuffer sb = new StringBuffer(testString);
    String reverseString = sb.reverse().toString();

    if(testString.equalsIgnoreCase(reverseString)) {
        return true;
    else {
        return false;
    }
}

Ответ 28

Много способов сделать это. Я думаю, что ключ должен сделать это наиболее эффективным способом (без обхода строки). Я бы сделал это как массив char, который можно легко отменить (используя С#).

string mystring = "abracadabra";

char[] str = mystring.ToCharArray();
Array.Reverse(str);
string revstring = new string(str);

if (mystring.equals(revstring))
{
    Console.WriteLine("String is a Palindrome");
}

Ответ 29

В Ruby, преобразование в нижний регистр и удаление всего не алфавитного:

def isPalindrome( string )
    ( test = string.downcase.gsub( /[^a-z]/, '' ) ) == test.reverse
end

Но это похоже на обман, не так ли? Нет указателей или чего-то еще! Таким образом, здесь также есть версия C, но без прошивки штриховки и символа:

#include <stdio.h>
int isPalindrome( char * string )
{
    char * i = string;
    char * p = string;
    while ( *++i ); while ( i > p && *p++ == *--i );
    return i <= p && *i++ == *--p;
}
int main( int argc, char **argv )
{
    if ( argc != 2 )
    {
        fprintf( stderr, "Usage: %s <word>\n", argv[0] );
        return -1;
    }
    fprintf( stdout, "%s\n", isPalindrome( argv[1] ) ? "yes" : "no" );
    return 0;
}

Хорошо, это было весело - я получаю задание; ^)

Ответ 30

Perl:

sub is_palindrome($)
{
  $s = lc(shift); # ignore case
  $s =~ s/\W+//g; # consider only letters, digits, and '_'
  $s eq reverse $s;
}

Он игнорирует регистр и полоски не буквенно-цифровых символов (он не зависит от локали и юникода).