Como verifico se um número é um palíndromo?


127

Como verifico se um número é um palíndromo?

Qualquer língua. Qualquer algoritmo. (exceto o algoritmo de transformar o número em uma sequência e depois reverter a sequência).


5
Você pode descobrir o tamanho do número inteiro em bits? se sim, diga A é o não e s é o tamanho B = A << s / 2 verifique se A&B == 2 ^ s-1 - 2 ^ (s / 2) + 1
Nitin Garg

10
O que há de errado em 'transformar o número em uma string e depois invertê-la'?
Coronel Panic

Comece por definir o que numbere is a palindromesignifica neste contexto: como sobre 13E31 (dez base)? 01210 (zero inicial)? + 10-10 + 1 (ternário balanceado de cinco dígitos)?
greybeard

Respostas:


128

Este é um dos problemas do Project Euler . Quando o resolvi em Haskell, fiz exatamente o que você sugere, converte o número em uma String. É então trivial verificar se a string é um palíndromo. Se o desempenho é bom o suficiente, por que se preocupar em torná-lo mais complexo? Ser um pallindrome é uma propriedade lexical e não matemática.


14
De fato. Qualquer algoritmo que você criar terá que pelo menos dividir o número em dígitos da base 10, que são 90% convertidos em uma sequência de qualquer maneira.
Blorgbeard sai em 13/10/08

5
Definitivamente, é um truque interessante convertê-lo em uma string, mas meio que derrota o ponto se você for perguntado sobre isso em uma entrevista, porque o ponto seria determinar se você entende o módulo.
Robert Noack

7
@ Robert Noack - o entrevistador pode pedir que você descreva um algoritmo para converter um número inteiro em uma string, o que obviamente exige que você entenda o módulo.
Steve314

@ Steve314 to describe an algorithm to convert an integer to a string, which of course requires you to understand modulo- não. Computar no sistema de números de destino, poder adicionar serve (pense em como você costuma converter de decimal para binário - ser usado para pensar que computação significa binário não significa que você não pode fazer, por exemplo, aritmética decimal (e você pode fazer conversão de binário para decimal sem divisão ou módulo 2) #
greybeard 16/16

@greybeard - Estou assumindo que a aritmética é feita no tipo que suporta aritmética e as operações de string são feitas no tipo que suporta operações de string - que é a divisão e o módulo / restante para o número inteiro e os caracteres anteriores à string. Claro que você pode implementar aritmética em seqüências de caracteres para si mesmo, mas (1) você realmente vai? Apenas para converter um número inteiro em uma string? E (2), embora você possa lidar com isso (ineficientemente) sem ele, precisará entender os restos em algum momento - você não tem uma aritmética inteira inteira em strings sem isso.
Steve314

269

Para qualquer número:

n = num;
rev = 0;
while (num > 0)
{
    dig = num % 10;
    rev = rev * 10 + dig;
    num = num / 10;
}

Se n == reventão numé um palíndromo:

cout << "Number " << (n == rev ? "IS" : "IS NOT") << " a palindrome" << endl;

isso é o que eu vim w / também. Acho que não faz sentido postar agora. +1
Esteban Araya

Isso pressupõe que rev seja inicializado em zero?
Justsalt 15/10/08

Sim Justsalt. A variável rev é inicializada em zero.
Jorge Ferreira

31
Nota para os transeuntes: se implementar isso em um idioma que manteria a parte fracionária da numdivisão posterior (digitação mais solta), você precisará fazer isso num = floor(num / 10).
Wiseguy

22
Esta solução não está totalmente certa. dig variável possivelmente pode estourar. Por exemplo, suponho que o tipo de num seja int, o valor seja quase inteiro.
Jiaji Li

24
def ReverseNumber(n, partial=0):
    if n == 0:
        return partial
    return ReverseNumber(n // 10, partial * 10 + n % 10)

trial = 123454321
if ReverseNumber(trial) == trial:
    print("It's a Palindrome!")

Funciona apenas para números inteiros. Não está claro a partir da declaração do problema se números de ponto flutuante ou zeros à esquerda precisam ser considerados.


22

Acima da maioria das respostas que têm um problema trivial está a possibilidade de a variável int transbordar.

Consulte http://articles.leetcode.com/palindrome-number/

boolean isPalindrome(int x) {
    if (x < 0)
        return false;
    int div = 1;
    while (x / div >= 10) {
        div *= 10;
    }
    while (x != 0) {
        int l = x / div;
        int r = x % 10;
        if (l != r)
            return false;
        x = (x % div) / 10;
        div /= 100;
    }
    return true;
}

Falhará quando os números tiverem zeros. Exemplo: 10000021.
Viraj

14
int is_palindrome(unsigned long orig)
{
    unsigned long reversed = 0, n = orig;

    while (n > 0)
    {
        reversed = reversed * 10 + n % 10;
        n /= 10;
    }

    return orig == reversed;
}

9

Empurre cada dígito individual em uma pilha e depois solte-os. Se for o mesmo para a frente e para trás, é um palíndromo.


Como você pressiona cada dígito individual do número inteiro?
Esteban Araya

1
Algo parecido com: int firstDigit = originalNumber% 10; int tmpNumber = número original / 10; int secondDigit = tmpNumber% 10; .... até você terminar.
Grant Limberg

Isso não funcionará no contexto da pergunta LeetCode - nenhum espaço adicional é permitido.
holograma

8

Não notei nenhuma resposta que resolvesse esse problema sem espaço extra, ou seja, todas as soluções que vi usavam uma string ou outro número inteiro para reverter o número ou algumas outras estruturas de dados.

Embora linguagens como Java envolvam o estouro de números inteiros, esse comportamento é indefinido em linguagens como C. ( Tente reverter 2147483647 (Integer.MAX_VALUE) em Java ) A
solução alternativa poderia ser usar um longo ou algo parecido, mas, estilisticamente, não o faço. como essa abordagem.

Agora, o conceito de um número palindrômico é que o número deve ler o mesmo para a frente e para trás. Ótimo. Usando essas informações, podemos comparar o primeiro e o último dígito. Truque é que, para o primeiro dígito, precisamos da ordem do número. Digamos, 12321. Dividir isso por 10000 nos daria o primeiro. O 1 final pode ser recuperado usando o mod com 10. Agora, reduza-o para 232 (12321 % 10000)/10 = (2321)/10 = 232.. E agora, o 10000 precisaria ser reduzido por um fator de 2. Então, agora vamos para o código Java ...

private static boolean isPalindrome(int n) {
    if (n < 0)
        return false;

    int div = 1;
    // find the divisor
    while (n / div >= 10)
        div *= 10;

    // any number less than 10 is a palindrome
    while (n != 0) {
        int leading = n / div;
        int trailing = n % 10;
        if (leading != trailing)
            return false;

        // % with div gets rid of leading digit
        // dividing result by 10 gets rid of trailing digit
        n = (n % div) / 10;

        // got rid of 2 numbers, update div accordingly
        div /= 100;
    }
    return true;
}

Editado conforme a sugestão de Hardik para cobrir os casos em que há zeros no número.


6

No Python, existe uma maneira rápida e iterativa.

def reverse(n):
    newnum=0
    while n>0:
        newnum = newnum*10 + n % 10
        n//=10
    return newnum

def palindrome(n):
    return n == reverse(n)

Isso também evita problemas de memória com recursão (como erro StackOverflow em Java)


Feche, mas você está mudando n enquanto faz isso. Você quer armazenar o valor n original e fazer o retorno comparar com que, em vez
RGroppa

6

Maneira mais rápida que eu conheço:

bool is_pal(int n) {
    if (n % 10 == 0) return 0;
    int r = 0;
    while (r < n) {
        r = 10 * r + n % 10;
        n /= 10;
    }
    return n == r || n == r / 10;
}

120 (decimal) é um "palíndromo decimal"? Inacreditavelmente rápido e semelhante à resposta do eku .
greybeard

5

Apenas por diversão, este também funciona.

a = num;
b = 0;
if (a % 10 == 0)
  return a == 0;
do {
  b = 10 * b + a % 10;
  if (a == b)
    return true;
  a = a / 10;
} while (a > b);
return a == b;

5

exceto transformar o número em uma sequência e depois revertê-la.

Por que descartar essa solução? É fácil de implementar e legível . Se você foi perguntado com nenhum computador na mão se2**10-23 é um palíndromo decimal, você certamente o testaria escrevendo-o em decimal.

Pelo menos em Python, o slogan 'operações com strings são mais lentas que aritméticas' é realmente falso. Comparei o algoritmo aritmético de Smink com a simples reversão de stringint(str(i)[::-1]) . Não houve diferença significativa na velocidade - aconteceu que a reversão das cordas foi marginalmente mais rápida.

Em linguagens compiladas (C / C ++), o slogan pode se manter, mas corre-se o risco de erros de transbordamento com grandes números.

def reverse(n):
    rev = 0
    while n > 0:
        rev = rev * 10 + n % 10
        n = n // 10
    return rev

upper = 10**6

def strung():
    for i in range(upper):
        int(str(i)[::-1])

def arithmetic():
    for i in range(upper):
        reverse(i)

import timeit
print "strung", timeit.timeit("strung()", setup="from __main__ import strung", number=1)
print "arithmetic", timeit.timeit("arithmetic()", setup="from __main__ import arithmetic", number=1)

Resultados em segundos (quanto menor, melhor):

1.50960231881 aritmética 1.69729960569


4

Eu respondi ao problema de Euler usando uma maneira muito bruta-forçada. Naturalmente, havia um algoritmo muito mais inteligente em exibição quando cheguei ao novo segmento de fórum associado desbloqueado. Nomeadamente, um membro que passou pela alça Begoner tinha uma abordagem tão nova que decidi reimplementar minha solução usando seu algoritmo. Sua versão estava em Python (usando loops aninhados) e eu a reimplementei no Clojure (usando um único loop / recorrência).

Aqui para sua diversão:

(defn palindrome? [n]
  (let [len (count n)]
    (and
      (= (first n) (last n))
      (or (>= 1 (count n))
        (palindrome? (. n (substring 1 (dec len))))))))

(defn begoners-palindrome []
  (loop [mx 0
         mxI 0
         mxJ 0
         i 999
         j 990]
    (if (> i 100)
      (let [product (* i j)]
        (if (and (> product mx) (palindrome? (str product)))
          (recur product i j
            (if (> j 100) i (dec i))
            (if (> j 100) (- j 11) 990))
          (recur mx mxI mxJ
            (if (> j 100) i (dec i))
            (if (> j 100) (- j 11) 990))))
      mx)))

(time (prn (begoners-palindrome)))

Havia respostas do Common Lisp também, mas elas eram imperdoáveis ​​para mim.


1
Eu tentei alguns dos testes palíndricos "matemáticos" postados aqui, mas fiquei surpreso que essa versão baseada em strings fosse a mais rápida.
22430 Chris Colete

Talvez isso não deva surpreender - afinal, a maneira mais rápida de perceber que um número dado a você era um palíndromo foi lendo a primeira metade e depois lendo a segunda metade ao contrário, não fazendo nenhum tipo de aritmética
Zubin Mukerjee

4

Aqui está uma versão do esquema que constrói uma função que funcionará em qualquer base. Possui uma verificação de redundância: retorne falso rapidamente se o número for múltiplo da base (termina em 0).
E não reconstrói todo o número invertido, apenas metade.
É tudo o que precisamos.

(define make-palindrome-tester
   (lambda (base)
     (lambda (n)
       (cond
         ((= 0 (modulo n base)) #f)
         (else
          (letrec
              ((Q (lambda (h t)
                    (cond
                      ((< h t) #f)
                      ((= h t) #t)
                      (else
                       (let*
                           ((h2 (quotient h base))
                            (m  (- h (* h2 base))))
                         (cond
                           ((= h2 t) #t)
                           (else
                            (Q h2 (+ (* base t) m))))))))))
            (Q n 0)))))))

4

Solução recursiva em ruby, sem converter o número em string.

def palindrome?(x, a=x, b=0)
  return x==b if a<1
  palindrome?(x, a/10, b*10 + a%10)
end

palindrome?(55655)

3

Versão Golang:

package main

import "fmt"

func main() {
    n := 123454321
    r := reverse(n)
    fmt.Println(r == n)
}

func reverse(n int) int {
    r := 0
    for {
        if n > 0 {
            r = r*10 + n%10
            n = n / 10
        } else {
            break
        }
    }
    return r
}

2

Retire o primeiro e o último dígito e compare-os até acabar. Pode haver um dígito restante, ou não, mas, de qualquer forma, se todos os dígitos exibidos coincidirem, é um palíndromo.


2

Aqui está mais uma solução em c ++ usando modelos. Esta solução funcionará para comparação de cadeias palíndricas sem distinção entre maiúsculas e minúsculas.

template <typename bidirection_iter>
bool palindrome(bidirection_iter first, bidirection_iter last)
{
    while(first != last && first != --last)
    {
        if(::toupper(*first) != ::toupper(*last))
            return false;
        else
            first++;
    }
    return true;
}

1

um método com um fator constante um pouco melhor que o método @sminks:

num=n
lastDigit=0;
rev=0;
while (num>rev) {
    lastDigit=num%10;
    rev=rev*10+lastDigit;
    num /=2;
}
if (num==rev) print PALINDROME; exit(0);
num=num*10+lastDigit; // This line is required as a number with odd number of bits will necessary end up being smaller even if it is a palindrome
if (num==rev) print PALINDROME

1

aqui está uma versão #:

let reverseNumber n =
    let rec loop acc = function
    |0 -> acc
    |x -> loop (acc * 10 + x % 10) (x/10)    
    loop 0 n

let isPalindrome = function
    | x  when x = reverseNumber x -> true
    | _ -> false

1

Um número é palíndrico se sua representação de sequência for palíndrica:

def is_palindrome(s):
    return all(s[i] == s[-(i + 1)] for i in range(len(s)//2))

def number_palindrome(n):
    return is_palindrome(str(n))

1
def palindrome(n):
    d = []
    while (n > 0):
        d.append(n % 10)
        n //= 10
    for i in range(len(d)/2):
        if (d[i] != d[-(i+1)]):
            return "Fail."
    return "Pass."

1

Para verificar se o número fornecido é Palindrome ou não (código Java)

class CheckPalindrome{
public static void main(String str[]){
        int a=242, n=a, b=a, rev=0;
        while(n>0){
                    a=n%10;  n=n/10;rev=rev*10+a;
                    System.out.println(a+"  "+n+"  "+rev);  // to see the logic
               }
        if(rev==b)  System.out.println("Palindrome");
        else        System.out.println("Not Palindrome");
    }
}

1

Muitas das soluções postadas aqui invertem o número inteiro e o armazenam em uma variável que utiliza espaço extra O(n), mas aqui está uma solução com O(1)espaço.

def isPalindrome(num):
    if num < 0:
        return False
    if num == 0:
        return True
    from math import log10
    length = int(log10(num))
    while length > 0:
        right = num % 10
        left = num / 10**length
        if right != left:
            return False
        num %= 10**length
        num /= 10
        length -= 2
    return True

1

Eu sempre uso essa solução python devido à sua compacidade.

def isPalindrome(number):
    return int(str(number)[::-1])==number

4
Isso é compacto, mas o OP disse especificamente " exceto o algoritmo de transformar o número em uma string e depois invertê-la "
Edward

0

Tente o seguinte:

reverse = 0;
    remainder = 0;
    count = 0;
    while (number > reverse)
    {
        remainder = number % 10;
        reverse = reverse * 10 + remainder;
        number = number / 10;
        count++;
    }
    Console.WriteLine(count);
    if (reverse == number)
    {
        Console.WriteLine("Your number is a palindrome");
    }
    else
    {
        number = number * 10 + remainder;
        if (reverse == number)
            Console.WriteLine("your number is a palindrome");
        else
            Console.WriteLine("your number is not a palindrome");
    }
    Console.ReadLine();
}
}

0

Aqui está uma solução que utiliza listas como pilhas em python:

def isPalindromicNum(n):
    """
        is 'n' a palindromic number?
    """
    ns = list(str(n))
    for n in ns:
        if n != ns.pop():
            return False
    return True

estourar a pilha considera apenas o lado mais à direita do número para comparação e falha rapidamente ao reduzir verificações


0
 public class Numbers
 {
   public static void main(int givenNum)
   { 
       int n= givenNum
       int rev=0;

       while(n>0)
       {
          //To extract the last digit
          int digit=n%10;

          //To store it in reverse
          rev=(rev*10)+digit;

          //To throw the last digit
          n=n/10;
      }

      //To check if a number is palindrome or not
      if(rev==givenNum)
      { 
         System.out.println(givenNum+"is a palindrome ");
      }
      else
      {
         System.out.pritnln(givenNum+"is not a palindrome");
      }
  }
}

0
let isPalindrome (n:int) =
   let l1 = n.ToString() |> List.ofSeq |> List.rev
   let rec isPalindromeInt l1 l2 =
       match (l1,l2) with
       | (h1::rest1,h2::rest2) -> if (h1 = h2) then isPalindromeInt rest1 rest2 else false
       | _ -> true
   isPalindromeInt l1 (n.ToString() |> List.ofSeq)

0
checkPalindrome(int number)
{
    int lsd, msd,len;
    len = log10(number);
    while(number)
    {
        msd = (number/pow(10,len)); // "most significant digit"
        lsd = number%10; // "least significant digit"
        if(lsd==msd)
        {
            number/=10; // change of LSD
            number-=msd*pow(10,--len); // change of MSD, due to change of MSD
            len-=1; // due to change in LSD
            } else {return 1;}
    }
    return 0;
}

Solução ruim, ruim. O Log10 é uma operação muito lenta e de ponto flutuante. Não use isso.
Rok Kralj

0

Maneira recursiva, não muito eficiente, basta fornecer uma opção

(Código Python)

def isPalindrome(num):
    size = len(str(num))
    demoninator = 10**(size-1)
    return isPalindromeHelper(num, size, demoninator)

def isPalindromeHelper(num, size, demoninator):
    """wrapper function, used in recursive"""
    if size <=1:
        return True
    else:       
        if num/demoninator != num%10:
            return False
        # shrink the size, num and denominator
        num %= demoninator
        num /= 10
        size -= 2
        demoninator /=100
        return isPalindromeHelper(num, size, demoninator) 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.