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

Esteban Araya
la source
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.

Dan Dyer
la source
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;
Jorge Ferreira
la source
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.

Mark Ransom
la source
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;
}
Jiaji Li
la source
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;
}
Robert Gamble
la source
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.

Grant Limberg
la source
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.

Debosmit Ray
la source
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)

ytpillai
la source
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;
}
Fleurs
la source
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;
Toon Krijthe
la source
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

Colonel Panic
la source
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.

Chris Vest
la source
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)))))))
z5h
la source
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)
dre-hh
la source
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
}
Thomas Modeneis
la source
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.

Eli
la source
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;
}
VikramChopde
la source
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
eku
la source
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
Omu
la source
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))
Hughdbrown
la source
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."
Roche
la source
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");
    }
}
sort_01out
la source
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
0x0
la source
1

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

def isPalindrome(number):
    return int(str(number)[::-1])==number
user2343020
la source
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();
}
}
vivek
la source
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

lwm
la source
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");
      }
  }
}
BLaaaaaa
la source
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)
mario
la source
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;
}
MarianG
la source
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) 
user1552891
la source