Comment vérifier si un nombre est un palindrome?


127

Comment vérifier si un nombre est un palindrome?

N'importe quel langage. Tout algorithme. (sauf l'algorithme consistant à faire du nombre une chaîne puis à inverser la chaîne).


5
Pouvez-vous connaître la taille de l'entier en bits? si oui, dites A est le non et s est la taille B = A << s / 2 vérifiez si A&B == 2 ^ s-1 - 2 ^ (s / 2) + 1
Nitin Garg

10
Quel est le problème avec «faire du nombre une chaîne, puis inverser la chaîne»?
Colonel Panic

Commencez par définir ce que numberet is a palindromesignifiera dans ce contexte: qu'en est-il de 13E31 (base dix)? 01210 (zéro non significatif)? + 10-10 + 1 (ternaire équilibré à cinq chiffres)?
greybeard

Réponses:


128

C'est l' un des problèmes du projet Euler . Quand je l'ai résolu dans Haskell, j'ai fait exactement ce que vous suggérez, convertir le nombre en chaîne. Il est alors trivial de vérifier que la chaîne est un pallindrome. S'il fonctionne assez bien, pourquoi se donner la peine de le rendre plus complexe? Être un pallindrome est une propriété lexicale plutôt que mathématique.


14
En effet. Tout algorithme que vous créez devra au moins diviser le nombre en chiffres de base 10, ce qui est de toute façon converti à 90% en chaîne.
Blorgbeard sort

5
C'est certainement une astuce intéressante pour le convertir en chaîne, mais cela va à l'encontre de l'intérêt si on vous le demandait lors d'une interview, car le but serait de déterminer si vous comprenez modulo.
Robert Noack

7
@Robert Noack - l'intervieweur peut alors vous demander de décrire un algorithme pour convertir un entier en chaîne, ce qui vous oblige bien sûr à comprendre modulo.
Steve314

@ Steve314 to describe an algorithm to convert an integer to a string, which of course requires you to understand modulo- non. Calculer dans le système numérique cible, être capable d'ajouter fera l'affaire (pensez à la façon dont vous convertissez généralement du décimal au binaire - être utilisé pour penser que le calcul signifie binaire ne signifie pas que vous ne pouvez pas faire, par exemple, l' arithmétique décimale (et vous pouvez le faire conversion de binaire en décimal sans division ni modulo 2).
greybeard

@greybeard - Je suppose que l'arithmétique est effectuée sur le type qui prend en charge l'arithmétique et que les opérations sur les chaînes sont effectuées sur le type qui prend en charge les opérations sur les chaînes - c'est la division et le modulo / reste pour l'entier et les caractères préfixés pour la chaîne. Bien sûr, vous pouvez implémenter l'arithmétique sur les chaînes pour vous-même, mais (1) allez-vous vraiment le faire? Juste pour convertir un entier en chaîne ?, et (2) bien que vous puissiez gérer cela (de manière inefficace) sans cela, vous devrez comprendre les restes à un moment donné - vous n'avez pas d'arithmétique entière sur les chaînes sans cela.
Steve314

269

Pour tout nombre donné:

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

Si n == revalors numest un palindrome:

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

c'est ce que je suis venu avec moi aussi. Je suppose que cela n'a aucun sens de le publier maintenant. +1
Esteban Araya

Cela suppose-t-il que rev est initialisé à zéro?
Justsalt

Oui Justsalt. La variable rev est initialisée à zéro.
Jorge Ferreira

31
Remarque pour les passants: si vous implémentez ceci dans un langage qui conserverait la partie fractionnaire de la numdivision après (frappe plus lâche), vous devrez le faire num = floor(num / 10).
Wiseguy

22
Cette solution n'est pas totalement correcte. la variable dig pourrait déborder. Par exemple, je suppose que le type de num est int, la valeur est presque Integer.Max, son dernier chiffre est 789, en cas de creusement inversé, puis de dépassement de capacité.
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!")

Fonctionne uniquement pour les entiers. Il n'est pas clair d'après l'énoncé du problème si les nombres à virgule flottante ou les zéros non significatifs doivent être pris en compte.


22

Au-dessus de la plupart des réponses ayant un problème trivial est que la variable int pourrait éventuellement déborder.

Reportez-vous à 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;
}

Echouera lorsque les nombres ont des zéros. Exemple: 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

Poussez chaque chiffre individuel sur une pile, puis retirez-les. Si c'est la même chose en avant et en arrière, c'est un palindrome.


Comment poussez-vous chaque chiffre individuel de l'entier?
Esteban Araya

1
Quelque chose du genre: int firstDigit = originalNumber% 10; int tmpNumber = originalNumber / 10; int secondDigit = tmpNumber% 10; .... jusqu'à ce que vous ayez terminé.
Grant Limberg

Cela ne fonctionnera pas dans le contexte de la question LeetCode - aucun espace supplémentaire n'est autorisé.
hologramme du

8

Je n'ai pas remarqué de réponses qui résolvaient ce problème en n'utilisant pas d'espace supplémentaire, c'est-à-dire que toutes les solutions que j'ai vues utilisaient soit une chaîne, soit un autre entier pour inverser le nombre, ou d'autres structures de données.

Bien que des langages comme Java s'enroulent sur le débordement d'entier, ce comportement n'est pas défini dans des langages comme C. ( Essayez d'inverser 2147483647 (Integer.MAX_VALUE) en Java ) La
solution de contournement pourrait être d'utiliser un long ou quelque chose du genre mais, stylistiquement, je ne suis pas tout à fait comme cette approche.

Maintenant, le concept d'un nombre palindromique est que le nombre doit lire la même chose vers l'avant et vers l'arrière. Génial. En utilisant ces informations, nous pouvons comparer le premier chiffre et le dernier chiffre. L'astuce est, pour le premier chiffre, nous avons besoin de l'ordre du nombre. Disons, 12321. Diviser cela par 10 000 nous donnerait le premier 1. Le 1 de fin peut être récupéré en prenant le mod avec 10. Maintenant, pour réduire cela à 232 (12321 % 10000)/10 = (2321)/10 = 232.. Et maintenant, le 10000 devrait être réduit d'un facteur 2. Alors, passons maintenant au code 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;
}

Modifié selon la suggestion de Hardik pour couvrir les cas où il y a des zéros dans le nombre.


6

En Python, il existe un moyen rapide et itératif.

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

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

Cela évite également les problèmes de mémoire avec la récursivité (comme l'erreur StackOverflow en Java)


Fermer, mais vous faites muter n en faisant cela. Vous voulez stocker la valeur n originale et faire la comparaison de retour en utilisant cela à la place
RGroppa

6

Le moyen le plus rapide que je connaisse:

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 (décimal) est un "palindrome décimal"? Incroyablement rapide et similaire à la réponse d' eku .
greybeard

5

Juste pour le plaisir, celui-ci fonctionne également.

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

sauf en faisant du nombre une chaîne, puis en inversant la chaîne.

Pourquoi rejeter cette solution? C'est facile à mettre en œuvre et lisible . Si on vous demandait sans ordinateur à portée de main s'il 2**10-23s'agit d'un palindrome décimal, vous le testeriez sûrement en l'écrivant en décimal.

En Python au moins, le slogan «les opérations sur les chaînes sont plus lentes que l'arithmétique» est en fait faux. J'ai comparé l'algorithme arithmétique de Smink à une simple inversion de chaîneint(str(i)[::-1]) . Il n'y avait pas de différence significative de vitesse - il s'est produit que l'inversion des cordes était légèrement plus rapide.

Dans les langages compilés (C / C ++), le slogan peut tenir, mais on risque des erreurs de débordement avec de grands nombres.

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)

Résultats en quelques secondes (moins c'est mieux):

cordée 1.50960231881 arithmétique 1.69729960569


4

J'ai répondu au problème d'Euler d'une manière très brutale. Naturellement, il y avait un algorithme beaucoup plus intelligent à l'affichage lorsque je suis arrivé au nouveau fil de discussion associé déverrouillé. A savoir, un membre qui est passé par le manche Begoner avait une approche tellement originale que j'ai décidé de réimplémenter ma solution en utilisant son algorithme. Sa version était en Python (en utilisant des boucles imbriquées) et je l'ai réimplémentée dans Clojure (en utilisant une seule boucle / récurrence).

Ici pour votre amusement:

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

Il y avait aussi des réponses en Common Lisp, mais elles m'étaient impossible à croiser.


1
J'ai essayé certains des tests de palindrome "mathématiques" postés ici, mais j'ai été surpris que cette version basée sur des chaînes soit la plus rapide.
Chris Vest

Peut-être que cela ne devrait pas être surprenant - après tout, le moyen le plus rapide de réaliser un nombre qui vous était donné était un palindrome était de lire la première moitié puis de lire la seconde moitié à l'envers, pas en faisant une sorte d'arithmétique
Zubin Mukerjee

4

Voici une version de Scheme qui construit une fonction qui fonctionnera sur n'importe quelle base. Il a un contrôle de redondance: retourne false rapidement si le nombre est un multiple de la base (se termine par 0).
Et il ne reconstruit pas tout le nombre inversé, seulement la moitié.
C'est tout ce dont nous avons besoin.

(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

Solution récursive en ruby, sans convertir le nombre en chaîne.

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

Version 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

Soulevez le premier et le dernier chiffres et comparez-les jusqu'à ce que vous soyez à court. Il peut y avoir un chiffre à gauche, ou pas, mais de toute façon, si tous les chiffres sautés correspondent, c'est un palindrome.


2

Voici une autre solution en C ++ utilisant des modèles. Cette solution fonctionnera pour la comparaison de chaînes de palindrome insensible à la casse.

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

une méthode avec un facteur constant un peu meilleur que la méthode @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

voici une # version:

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 nombre est palindromique si sa représentation sous forme de chaîne est palindromique:

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

Pour vérifier que le numéro donné est Palindrome ou non (Java Code)

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

Un grand nombre des solutions affichées ici inverse l'entier et le stocke dans une variable qui utilise un espace supplémentaire O(n), mais voici une solution avec O(1)espace.

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

J'utilise toujours cette solution python en raison de sa compacité.

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

4
C'est compact, mais l'OP a spécifiquement dit " sauf l'algorithme consistant à faire du nombre une chaîne puis à inverser la chaîne "
Edward

0

Essaye ça:

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

Voici une solution utilisant des listes sous forme de piles en 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

sauter la pile ne considère que le côté le plus à droite du nombre pour la comparaison et il échoue rapidement à réduire les contrôles


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

Mauvaise, mauvaise solution. Log10 est une opération en virgule flottante très lente. Ne l'utilisez pas.
Rok Kralj

0

De manière récursive, pas très efficace, il suffit de fournir une option

(Code 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) 
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.