Bir numaranın bir palindrom olup olmadığını nasıl kontrol ederim?


127

Bir numaranın bir palindrom olup olmadığını nasıl kontrol ederim?

Herhangi bir dil. Herhangi bir algoritma. (sayıyı bir dizge yapma ve ardından dizeyi ters çevirme algoritması hariç).


5
Bit cinsinden tamsayının boyutunu bulabilir misin? evet ise, A'nın hayır olduğunu ve s'nin B = A olduğunu söyle << s / 2 A&B == 2 ^ s-1 - 2 ^ (s / 2) + 1
Nitin Garg

10
'Sayıyı bir dizge yapmak ve sonra dizgiyi tersine çevirmek'in nesi yanlış?
Albay Panic

Bu bağlamda neyi numberve ne is a palindromeanlama geldiğini tanımlayarak başlayın : peki ya 13E31 (on tabanında)? 01210 (baştaki sıfır)? + 10-10 + 1 (beş basamaklı dengeli üçlü)?
greybeard

Yanıtlar:


128

Bu, Euler Projesi sorunlarından biridir . Haskell'de çözdüğümde tam olarak sizin önerdiğiniz şeyi yaptım, sayıyı String'e çevirin. Daha sonra dizenin bir pallindrom olup olmadığını kontrol etmek önemsizdir. Yeterince iyi performans gösteriyorsa, neden onu daha karmaşık hale getirmeye çalışalım? Bir pallindrom olmak matematiksel olmaktan çok sözcüksel bir özelliktir.


14
Aslında. Yaptığınız herhangi bir algoritma, sayıyı en azından 10 taban haneye bölmek zorunda kalacaktır, bu da% 90'ı yine de bir dizeye dönüştürülür.
Blorgbeard

5
Bunu bir dizgeye dönüştürmek kesinlikle güzel bir numara, ancak bir röportajda size sorulsaydı, asıl mesele modulo'yu anlayıp anlamadığınızı belirlemek olurdu.
Robert Noack

7
@Robert Noack - görüşmeci daha sonra sizden bir tamsayıyı dizeye dönüştürmek için bir algoritma tanımlamanızı isteyebilir, bu da elbette modulo'yu anlamanızı gerektirir.
Steve314

@ Steve314 to describe an algorithm to convert an integer to a string, which of course requires you to understand modulo- hayır. Yaygın olarak ikili ondalık dönüştürmek nasıl düşünmek (yapacağız ekleyememe, hedef numarası sistemde Bilgisayar - düşünmek için kullanılan hesaplama araçlarının ikili , yapamayacağınız anlamına örneğin gelmez ondalık aritmetik (ve yapabilirsiniz yapmak ikiliden ondalık sayıya bölme veya modulo olmadan dönüştürme 2).
greybeard

@greybeard - Aritmetiğin aritmetiği destekleyen tür üzerinde yapıldığını ve dize işlemlerinin dize işlemlerini destekleyen tür üzerinde yapıldığını varsayıyorum - bu, tamsayı için bölme ve modulo / kalan ve dize için ön bekleyen karakterler. Tabii ki olabilir kendiniz için dizeleri üzerinde aritmetik uygulamak, ancak (1) Eğer gerçekten gidiyorsun? Sadece bir tamsayıyı dizgeye dönüştürmek için mi? Ve (2) bunu onsuz (verimsiz bir şekilde) halledebilmenize rağmen, bir noktada kalanları anlamanız gerekir - bu olmadan dizelerde tam bir tam sayı aritmetiğiniz yoktur.
Steve314

269

Herhangi bir numara için:

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

Eğer n == revo zaman numbir palindrom geçerli:

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

bu da w / geldiğim şey. sanırım şimdi yayınlamamın bir anlamı yok. +1
Esteban Araya

Bu, rev'in sıfıra başlatıldığını mı varsayıyor?
Justsalt

Evet Justsalt. Rev değişkeni sıfır olarak başlatılır.
Jorge Ferreira

31
Yoldan geçenler için not: Bunu, numbölümden sonraki bölümün kesirli bölümünü koruyacak bir dilde uyguluyorsanız (daha gevşek yazım), bunu yapmanız gerekir num = floor(num / 10).
Wiseguy

22
Bu çözüm tamamen doğru değil. değişken kazı muhtemelen taşabilir. Örneğin, num türünün int olduğunu varsayıyorum, değer neredeyse Tamsayı.Max, son basamağı 789, ters kazı, sonra taşma.
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!")

Yalnızca tamsayılar için çalışır. Kayan noktalı sayıların veya baştaki sıfırların dikkate alınması gerekip gerekmediği sorun bildiriminden açık değildir.


22

Önemsiz bir problemi olan cevapların çoğunun üstünde, int değişkeninin muhtemelen taşmasıdır.

Bakın 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;
}

Sayıların içinde sıfır olduğunda başarısız olur. Örnek: 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

Her bir rakamı bir yığının üzerine itin, ardından onları çıkarın. İleri ve geri aynıysa, bu bir palindromdur.


Tam sayıdan her bir rakamı nasıl itiyorsunuz?
Esteban Araya

1
Şu satırlar boyunca bir şey: int firstDigit = originalNumber% 10; int tmpNumber = orijinalSayı / 10; int secondDigit = tmpNumber% 10; .... bitene kadar.
Grant Limberg

Bu LeetCode sorusu bağlamında çalışmayacaktır - ek alana izin verilmez.
hologram

8

Bu sorunu fazladan boşluk kullanmadan çözen herhangi bir yanıt fark etmedim, yani gördüğüm tüm çözümlerde ya bir dizge ya da sayıyı tersine çevirmek için başka bir tam sayı ya da başka veri yapıları kullanıldı.

Java gibi diller tamsayı taşması üzerine sarılsa da, bu davranış C gibi dillerde tanımlanmamıştır. ( Java'da 2147483647 (Tamsayı.MAX_VALUE) ters çevirmeyi deneyin )
Geçici çözüm uzun veya başka bir şey kullanmak olabilir, ancak biçimsel olarak pek bilmiyorum bu yaklaşım gibi.

Şimdi, palindromik sayı kavramı, sayının aynı ileri ve geri okuması gerektiğidir. Harika. Bu bilgiyi kullanarak ilk rakam ile son rakamı karşılaştırabiliriz. İşin püf noktası, ilk rakam için numaranın sırasına ihtiyacımız var. 12321. Bunu 10000'e bölmek bize lider 1'i getirir. Sondaki 1, modun 10 ile alınmasıyla alınabilir. Şimdi, bunu 232'ye düşürmek için (12321 % 10000)/10 = (2321)/10 = 232. Ve şimdi, 10000'in 2 kat azaltılması gerekecek. Şimdi Java koduna geçelim ...

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

Sayıda sıfır olan durumları kapsayacak şekilde Hardik'in önerisine göre düzenlenmiştir .


6

Python'da hızlı ve yinelemeli bir yol var.

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

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

Bu aynı zamanda özyinelemeyle ilgili bellek sorunlarını da önler (Java'daki StackOverflow hatası gibi)


Kapat, ama bunu yaparken mutasyona uğruyorsun. Orijinal n değerini saklamak ve bunun yerine geri dönüş karşılaştırmasını yapmak istiyorsunuz
RGroppa

6

Bildiğim en hızlı yol:

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 (ondalık) bir "ondalık palindrom" mu? İnanılmaz derecede hızlı ve eku'nun cevabına benzer .
greybeard

5

Sadece eğlence için bu da işe yarıyor.

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

sayıyı bir dizge yapmak ve sonra dizeyi tersine çevirmek dışında.

Neden bu çözümü reddedelim? Uygulanması ve okunması kolay . Elinizde bilgisayar olmadan 2**10-23ondalık palindrom olup olmadığı sorulsaydı , kesinlikle ondalık olarak yazarak test edersiniz.

En azından Python'da, 'dizge işlemleri aritmetikten daha yavaştır' sloganı aslında yanlıştır. Smink'in aritmetik algoritmasını basit tel ters çevirme ile karşılaştırdım int(str(i)[::-1]). Hızda önemli bir fark yoktu - dizi tersine çevrilmesi marjinal olarak daha hızlıydı.

Derlenmiş dillerde (C / C ++) slogan geçerli olabilir, ancak biri büyük sayılarda taşma hatalarını riske atar.

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)

Saniyeler içinde sonuçlar (ne kadar düşük olursa o kadar iyidir):

gergin 1.50960231881 aritmetik 1.69729960569


4

Euler sorununa çok kaba bir şekilde cevap verdim. Doğal olarak, yeni kilidi açılmış ilişkili forum başlığına geldiğimde ekranda çok daha akıllı bir algoritma vardı. Yani, Begoner'a saplanan bir üye o kadar alışılmadık bir yaklaşıma sahipti ki, onun algoritmasını kullanarak çözümümü yeniden uygulamaya karar verdim. Onun sürümü Python'daydı (iç içe döngüler kullanıyordu) ve ben onu Clojure'da yeniden uyguladım (tek bir döngü / yineleme kullanarak).

Eğlenmeniz için burada:

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

Common Lisp cevapları da vardı, ama benim için çözülemezlerdi.


1
Burada yayınlanan bazı "matematiksel" palindrom testlerini denedim, ancak bu dizi tabanlı sürümün daha hızlı olmasına şaşırdım.
Chris Vest

Belki bu şaşırtıcı olmamalı - sonuçta, size verilen bir sayıyı fark etmenin en hızlı yolu, herhangi bir aritmetik yapmak yerine ilk yarıyı okuyup sonra ikinci yarıyı geriye doğru
okumaktı

4

İşte herhangi bir tabana karşı çalışacak bir fonksiyon oluşturan bir Scheme versiyonu. Fazlalık kontrolü vardır: sayı tabanın katı ise (0 ile biten) hızlı bir şekilde yanlış döndür.
Ve tüm ters çevrilmiş sayıyı yeniden oluşturmaz, sadece yarısını.
Tek ihtiyacımız olan bu.

(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

Ruby'de sayıyı dizgeye dönüştürmeden özyinelemeli çözüm.

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

Golang versiyonu:

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

İlk ve son rakamları çıkarın ve bitene kadar bunları karşılaştırın. Solda bir rakam olabilir veya olmayabilir, ancak her iki durumda da, çıkarılan tüm rakamlar eşleşirse, bu bir palindromdur.


2

Şablonları kullanarak c ++ 'da bir çözüm daha. Bu çözüm, büyük / küçük harfe duyarlı olmayan palindrom dize karşılaştırması için çalışacaktır.

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

@sminks yönteminden biraz daha iyi sabit faktörlü bir yöntem:

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

işte af # sürümü:

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

Dize gösterimi palindromik ise bir sayı palindromiktir:

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

Verilen numaranın Palindrome olup olmadığını kontrol etmek için (Java Kodu)

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

Burada yayınlanan çözümlerin çoğu, tamsayıyı ters çevirir ve onu fazladan alan kullanan bir değişkende saklar O(n), ancak burada O(1)boşluklu bir çözüm vardır .

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

Kompaktlığı nedeniyle her zaman bu python çözümünü kullanıyorum.

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

4
Yani kompakt olmakla OP özellikle "dedi dize ters ardından numaralı bir dize yapma ve algoritma hariç "
Edward

0

Bunu dene:

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

İşte listeleri python'da yığınlar olarak kullanan bir çözüm:

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

Yığını patlatmak, karşılaştırma için sayının yalnızca en sağ tarafını dikkate alır ve kontrolleri azaltmada hızlı başarısız olur


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

Kötü, kötü çözüm. Log10 gerçekten yavaş, kayan noktalı bir işlemdir. Bunu kullanmayın.
Rok Kralj

0

Özyinelemeli yol, çok verimli değil, sadece bir seçenek sunun

(Python kodu)

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) 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.