Come posso verificare se un numero è un palindromo?


127

Come posso verificare se un numero è un palindromo?

Qualunque lingua. Qualsiasi algoritmo. (tranne l'algoritmo di trasformazione del numero in stringa e quindi inversione della stringa).


5
Riesci a scoprire la dimensione dell'intero in bit? se sì, dì A è il no e s è la dimensione B = A << s / 2 controlla se A&B == 2 ^ s-1 - 2 ^ (s / 2) + 1
Nitin Garg

10
Cosa c'è di sbagliato nel "rendere il numero una stringa e quindi invertire la stringa"?
Colonnello Panic,

Inizia definendo cosa numbere cosa is a palindromesignificherà in questo contesto: che ne dici di 13E31 (base dieci)? 01210 (zero iniziale)? + 10-10 + 1 (ternario bilanciato a cinque cifre)?
greybeard

Risposte:


128

Questo è uno dei problemi di Project Euler . Quando l'ho risolto in Haskell ho fatto esattamente quello che mi hai suggerito, convertendo il numero in una stringa. È quindi banale verificare che la stringa sia un pallindrome. Se funziona abbastanza bene, allora perché preoccuparsi di renderlo più complesso? Essere un pallindromo è una proprietà lessicale piuttosto che matematica.


14
Infatti. Qualsiasi algoritmo creato dovrà almeno dividere il numero in cifre in base 10, che viene comunque convertito al 90% in una stringa.
Blorgbeard esce il

5
È sicuramente un trucco per convertirlo in una stringa, ma in qualche modo sconfigge il punto se ti è stato chiesto in un'intervista perché il punto sarebbe determinare se hai capito il modulo.
Robert Noack,

7
@Robert Noack - l'intervistatore può quindi chiederti di descrivere un algoritmo per convertire un numero intero in una stringa, che ovviamente richiede di comprendere il modulo.
Steve314,

@ Steve314 to describe an algorithm to convert an integer to a string, which of course requires you to understand modulo- no. Il calcolo nel sistema dei numeri di destinazione, la possibilità di aggiungere farà (pensa a come converti comunemente da decimale a binario - essere usato per pensare il calcolo significa binario non significa che non puoi fare, ad esempio, l' aritmetica decimale (e puoi farlo conversione da binario a decimale senza divisione o modulo 2)
greybeard,

@greybeard - Suppongo che l'aritmetica venga eseguita sul tipo che supporta l'aritmetica e che le operazioni sulle stringhe vengano eseguite sul tipo che supporta le operazioni sulle stringhe: ovvero divisione e modulo / resto per l'intero e anteporre caratteri per la stringa. Ovviamente puoi implementare l'aritmetica sulle stringhe per te, ma (1) lo farai davvero? Solo per convertire un numero intero in una stringa ?, e (2) sebbene sia possibile gestirlo (in modo inefficiente) senza di esso, a un certo punto dovrai capire i resti - non hai un'aritmetica di numeri interi completa sulle stringhe senza quella.
Steve314,

269

Per un determinato numero:

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

Se n == revquindi numè un palindromo:

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

è quello che mi è venuto in mente anche io. Immagino che non abbia senso pubblicarlo adesso. +1
Esteban Araya,

Sta assumendo che rev sia inizializzato a zero?
Justsalt,

Sì Justsalt. La variabile rev viene inizializzata su zero.
Jorge Ferreira,

31
Nota per i passanti: se si implementa questo in un linguaggio che manterrebbe la parte frazionaria di numafter division (digitazione più libera), è necessario farlo num = floor(num / 10).
Wiseguy,

22
Questa soluzione non è assolutamente giusta. lo scavo variabile potrebbe traboccare. Ad esempio, suppongo che il tipo di num sia int, il valore è quasi Integer.Max, la sua ultima cifra è 789, quando scava al contrario, quindi trabocca.
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!")

Funziona solo per numeri interi. Non è chiaro dall'affermazione del problema se devono essere considerati numeri in virgola mobile o zeri iniziali.


22

Sopra la maggior parte delle risposte che hanno un problema banale è che la variabile int potrebbe probabilmente traboccare.

Fare riferimento a 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;
}

Fallirà quando i numeri contengono zeri. Esempio: 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

Spingi ogni singola cifra su una pila, quindi saltale via. Se è lo stesso avanti e indietro, è un palindromo.


Come si spinge ogni singola cifra dall'intero?
Esteban Araya,

1
Qualcosa sulla falsariga di: int firstDigit = originalNumber% 10; int tmpNumber = originalNumber / 10; int secondDigit = tmpNumber% 10; .... fino a quando non hai finito.
Grant Limberg,

Questo non funzionerà nel contesto della domanda LeetCode: non è consentito spazio aggiuntivo.
ologramma

8

Non ho notato alcuna risposta che risolva questo problema senza spazio aggiuntivo, ovvero tutte le soluzioni che ho visto hanno usato una stringa o un altro numero intero per invertire il numero o alcune altre strutture di dati.

Sebbene linguaggi come Java si sovrappongano a overflow di numeri interi, questo comportamento non è definito in linguaggi come C. ( Prova a invertire 2147483647 (Integer.MAX_VALUE) in Java ) La
soluzione alternativa potrebbe essere quella di utilizzare un long o qualcosa ma, stilisticamente, non abbastanza come questo approccio.

Ora, il concetto di un numero palindromico è che il numero dovrebbe leggere lo stesso avanti e indietro. Grande. Utilizzando queste informazioni, possiamo confrontare la prima cifra e l'ultima cifra. Il trucco è, per la prima cifra, abbiamo bisogno dell'ordine del numero. Diciamo, 12321. Dividendo questo per 10000 ci porterebbe il primo 1. Il trailing 1 può essere recuperato prendendo la mod con 10. Ora, per ridurlo a 232 (12321 % 10000)/10 = (2321)/10 = 232.. E ora, il 10000 dovrebbe essere ridotto di un fattore 2. Quindi, ora al codice 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;
}

Modificato secondo il suggerimento di Hardik per coprire i casi in cui ci sono zero nel numero.


6

In Python esiste un modo rapido e iterativo.

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

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

Questo impedisce anche problemi di memoria con ricorsione (come errore StackOverflow in Java)


Chiudi, ma stai mutando n mentre lo fai. Volete memorizzare il valore originale n e fare il confronto del ritorno usando quello invece
RGroppa

6

Il modo più veloce che conosco:

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 (decimale) è un "palindromo decimale"? Incredibilmente veloce e simile alla risposta di Eku .
greybeard,

5

Solo per divertimento, anche questo funziona.

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

tranne che per rendere il numero una stringa e quindi invertire la stringa.

Perché respingere quella soluzione? È facile da implementare e leggibile . Se ti chiedessero senza computer a portata di mano se si 2**10-23tratta di un palindromo decimale, lo testeresti sicuramente scrivendolo in decimale.

Almeno in Python, lo slogan "le operazioni sulle stringhe sono più lente dell'aritmetica" è in realtà falso. Ho confrontato l'algoritmo aritmetico di Smink con la semplice inversione di stringa int(str(i)[::-1]). Non c'è stata una differenza significativa nella velocità: è successo che l'inversione della stringa era leggermente più veloce.

Nei linguaggi compilati (C / C ++) lo slogan potrebbe contenere, ma si rischiano errori di overflow con numeri grandi.

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)

Risultati in secondi (inferiore è meglio):

infilata 1.50960231881 aritmetica 1.69729960569


4

Ho risposto al problema di Eulero usando un modo molto brutale. Ovviamente, c'era un algoritmo molto più intelligente in mostra quando sono arrivato al nuovo thread del forum associato sbloccato. Vale a dire, un membro che è andato per la prima volta Begoner ha avuto un approccio così nuovo, che ho deciso di reimplementare la mia soluzione usando il suo algoritmo. La sua versione era in Python (usando loop nidificati) e l'ho reimplementata in Clojure (usando un singolo loop / recur).

Qui per il tuo divertimento:

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

C'erano anche risposte del Common Lisp, ma per me erano inaffidabili.


1
Ho provato alcuni dei test "matematici" sul palindromo pubblicati qui, ma sono rimasto sorpreso dal fatto che questa versione basata su stringhe fosse la più veloce.
Chris Vest,

Forse questo non dovrebbe sorprendere - dopotutto, il modo più veloce in cui potresti realizzare un numero che ti è stato dato è stato un palindromo era di leggere la prima metà e poi di leggere la seconda metà all'indietro, non facendo alcun tipo di aritmetica
Zubin Mukerjee,

4

Ecco una versione di Scheme che costruisce una funzione che funzionerà su qualsiasi base. Ha un controllo di ridondanza: restituisce false rapidamente se il numero è un multiplo della base (termina con 0).
E non ricostruisce l'intero numero invertito, solo la metà.
Questo è tutto ciò di cui abbiamo bisogno.

(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

Soluzione ricorsiva in rubino, senza convertire il numero in stringa.

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

Versione 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

Rimuovi la prima e l'ultima cifra e confrontale fino allo scadere. Potrebbe esserci una cifra a sinistra o no, ma in entrambi i casi, se tutte le cifre spuntate corrispondono, è un palindromo.


2

Ecco un'altra soluzione in c ++ usando i template. Questa soluzione funzionerà per il confronto tra maiuscole e minuscole maiuscole e minuscole.

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

un metodo con un fattore costante leggermente migliore rispetto al metodo @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

ecco una versione #:

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

Un numero è palindromico se la sua rappresentazione di stringa è palindromica:

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

Per verificare che il numero indicato sia Palindrome o no (codice 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

Molte delle soluzioni pubblicate qui inverte il numero intero e lo memorizza in una variabile che utilizza lo spazio extra che è O(n), ma qui è una soluzione con O(1)spazio.

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

Uso sempre questa soluzione Python per la sua compattezza.

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

4
Questo è compatto, ma l'OP ha detto specificamente " tranne l'algoritmo di rendere il numero una stringa e quindi invertire la stringa "
Edward

0

Prova questo:

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

Ecco una soluzione che usa gli elenchi come stack in 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

il pop-up dello stack considera solo il lato più a destra del numero per il confronto e non riesce a ridurre rapidamente i controlli


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

Cattiva, cattiva soluzione. Log10 è un'operazione molto lenta in virgola mobile. Non usare questo.
Rok Kralj,

0

Modo ricorsivo, non molto efficiente, basta fornire un'opzione

(Codice 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) 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.