Bagaimana cara saya memeriksa apakah suatu angka adalah palindrom?


127

Bagaimana cara saya memeriksa apakah suatu angka adalah palindrom?

Bahasa apapun. Algoritma apa saja. (kecuali algoritma membuat angka menjadi string dan kemudian membalikkan string).


5
Bisakah Anda mengetahui ukuran integer dalam bit? jika ya, Say A adalah no dan s adalah ukuran B = A << s / 2 periksa apakah A&B == 2 ^ s-1 - 2 ^ (s / 2) + 1
Nitin Garg

10
Apa yang salah dengan 'membuat angka menjadi string dan kemudian membalikkan string'?
Kolonel Panic

Mulailah dengan mendefinisikan apa numberdan is a palindromeakan berarti dalam konteks ini: bagaimana dengan 13E31 (basis sepuluh)? 01210 (nol di depan)? + 10-10 + 1 (lima digit terner seimbang)?
greybeard

Jawaban:


128

Ini adalah salah satu masalah Project Euler . Ketika saya menyelesaikannya di Haskell saya melakukan persis apa yang Anda sarankan, ubah nomornya menjadi String. Maka sepele untuk memeriksa bahwa string adalah pallindrome. Jika kinerjanya cukup baik, lalu mengapa repot membuatnya lebih kompleks? Menjadi pallindrome adalah properti leksikal dan bukan matematika.


14
Memang. Algoritma apa pun yang Anda buat harus setidaknya membagi angka menjadi basis-10 digit, yang merupakan 90% dikonversi ke string.
Blorgbeard keluar

5
Ini jelas merupakan trik yang rapi untuk mengubahnya menjadi string tetapi agak mengalahkan intinya jika Anda ditanyai ini pada sebuah wawancara karena intinya adalah untuk menentukan apakah Anda memahami modulo.
Robert Noack

7
@Robert Noack - pewawancara kemudian dapat meminta Anda untuk mendeskripsikan algoritma untuk mengkonversi integer ke string, yang tentu saja mengharuskan Anda untuk memahami modulo.
Steve314

@ Steve314 to describe an algorithm to convert an integer to a string, which of course requires you to understand modulo- tidak. Komputasi dalam sistem angka target, dapat menambahkan akan dilakukan (pikirkan bagaimana Anda biasanya mengkonversi dari desimal ke biner - terbiasa berpikir perhitungan berarti biner tidak berarti Anda tidak dapat melakukan, misalnya, aritmatika desimal (dan Anda dapat melakukan konversi dari biner ke desimal tanpa pembagian atau modulo 2)
greybeard

@ Greybeard - Saya mengasumsikan aritmatika dilakukan pada tipe yang mendukung aritmatika dan operasi string dilakukan pada tipe yang mendukung operasi string - itu adalah pembagian dan modulo / sisanya untuk integer dan karakter yang diawali untuk string. Tentu saja Anda dapat menerapkan aritmatika pada string untuk Anda sendiri, tetapi (1) apakah Anda benar-benar akan melakukannya? Hanya untuk mengonversi bilangan bulat menjadi string ?, dan (2) meskipun Anda dapat menangani ini (tidak efisien) tanpa itu, Anda harus memahami sisanya di beberapa titik - Anda tidak memiliki aritmatika bilangan bulat lengkap pada string tanpa itu.
Steve314

269

Untuk nomor yang diberikan:

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

Jika n == revdemikian numadalah palindrome:

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

itu yang saya tuju juga. saya rasa tidak masuk akal saya mempostingnya sekarang. +1
Esteban Araya

Apakah ini dengan asumsi bahwa rev diinisialisasi ke nol?
Justsalt

Ya Justsalt. Variabel rev diinisialisasi ke nol.
Jorge Ferreira

31
Catatan untuk orang yang lewat: jika menerapkan ini dalam bahasa yang akan menjaga bagian pecahan dari numsetelah pembagian (mengetik lebih longgar), Anda harus membuatnya num = floor(num / 10).
Wiseguy

22
Solusi ini tidak sepenuhnya benar. penggalian variabel mungkin meluap. Sebagai contoh, saya berasumsi jenis num adalah int, nilainya hampir Integer.Max, digit terakhirnya adalah 789, ketika membalikkan menggali, lalu melimpah.
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!")

Hanya berfungsi untuk bilangan bulat. Tidak jelas dari pernyataan masalah jika angka floating point atau nol terkemuka perlu dipertimbangkan.


22

Di atas sebagian besar jawaban yang memiliki masalah sepele adalah bahwa variabel int mungkin meluap.

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

Akan gagal ketika angka memiliki nol di dalamnya. Contoh: 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

Dorong setiap digit individu ke tumpukan, lalu lepaskan. Jika maju dan mundur sama, itu adalah palindrom.


Bagaimana Anda mendorong setiap digit individu dari integer?
Esteban Araya

1
Sesuatu di sepanjang baris: int firstDigit = originalNumber% 10; int tmpNumber = originalNumber / 10; int secondDigit = tmpNumber% 10; .... sampai selesai.
Grant Limberg

Ini tidak akan berfungsi dalam konteks pertanyaan LeetCode - tidak ada ruang tambahan yang diizinkan.
hologram

8

Saya tidak melihat jawaban yang memecahkan masalah ini tanpa menggunakan ruang tambahan, yaitu, semua solusi yang saya lihat menggunakan string, atau integer lain untuk membalikkan angka, atau beberapa struktur data lainnya.

Meskipun bahasa seperti Java membungkus integer overflow, perilaku ini tidak terdefinisi dalam bahasa seperti C. ( Coba membalikkan 2147483647 (Integer.MAX_VALUE) di Jawa )
Penyelesaiannya bisa dengan menggunakan panjang atau sesuatu tetapi, secara stylistically, saya tidak cukup seperti pendekatan itu.

Sekarang, konsep bilangan palindromik adalah bilangan tersebut harus membaca maju dan mundur yang sama. Bagus. Dengan menggunakan informasi ini, kita dapat membandingkan digit pertama dan digit terakhir. Triknya, untuk digit pertama, kita perlu urutan nomornya. Katakanlah, 12321. Membagi ini dengan 10.000 akan memberi kita yang pertama. 1. Trailing 1 dapat diambil dengan mengambil mod dengan 10. Sekarang, untuk mengurangi ini ke 232 (12321 % 10000)/10 = (2321)/10 = 232.. Dan sekarang, 10000 perlu dikurangi dengan faktor 2. Jadi, sekarang ke kode 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;
}

Diedit sesuai saran Hardik untuk membahas kasus-kasus di mana ada nol dalam jumlah.


6

Dalam Python, ada cara yang cepat dan berulang.

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

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

Ini juga mencegah masalah memori dengan rekursi (seperti kesalahan StackOverflow di Jawa)


Tutup, tetapi Anda bermutasi dan saat melakukan ini. Anda ingin menyimpan nilai n asli dan melakukan perbandingan pengembalian menggunakan itu
RGroppa

6

Cara tercepat yang saya tahu:

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 (desimal) adalah "palindrome desimal"? Sangat cepat, dan mirip dengan jawaban eku .
greybeard

5

Hanya untuk bersenang-senang, ini juga berfungsi.

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

kecuali membuat nomor string dan kemudian membalikkan string.

Mengapa mengabaikan solusi itu? Mudah diimplementasikan dan dibaca . Jika Anda ditanya tanpa komputer apakah 2**10-23palindrom desimal, Anda pasti akan mengujinya dengan menuliskannya dalam desimal.

Setidaknya dalam Python, slogan 'operasi string lebih lambat daripada aritmatika' sebenarnya salah. Saya membandingkan algoritma aritmatika Smink dengan pembalikan string sederhana int(str(i)[::-1]). Tidak ada perbedaan kecepatan yang signifikan - itu terjadi pembalikan string sedikit lebih cepat.

Dalam bahasa yang dikompilasi (C / C ++) slogan mungkin berlaku, tetapi satu risiko meluap kesalahan dengan jumlah besar.

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)

Hasil dalam detik (lebih rendah lebih baik):

dirangkai 1.50960231881 aritmatika 1.69729960569


4

Saya menjawab masalah Euler menggunakan cara yang sangat kasar. Tentu saja, ada algoritma yang jauh lebih cerdas saat saya membuka utas forum terkait yang tidak dikunci. Yaitu, seorang anggota yang pergi dengan pegangan Begoner memiliki pendekatan baru, sehingga saya memutuskan untuk mengimplementasikan kembali solusi saya menggunakan algoritma-nya. Versi-nya menggunakan Python (menggunakan loop bersarang) dan saya menerapkannya kembali di Clojure (menggunakan satu loop / berulang).

Di sini untuk hiburan Anda:

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

Ada juga jawaban Common Lisp, tetapi tidak dapat saya ungkapkan.


1
Saya mencoba beberapa tes palindrom "matematis" yang diposting di sini, tetapi terkejut bahwa versi berbasis string ini lebih cepat.
Chris Vest

Mungkin ini seharusnya tidak mengejutkan - lagipula, cara tercepat Anda dapat menyadari angka yang diberikan kepada Anda adalah palindrom adalah dengan membaca paruh pertama lalu membaca paruh kedua mundur, bukan dengan melakukan segala macam aritmatika
Zubin Mukerjee

4

Berikut adalah versi Skema yang membangun fungsi yang akan bekerja melawan basis apa pun. Ini memiliki pemeriksaan redundansi: mengembalikan false dengan cepat jika nomor tersebut merupakan kelipatan dari basis (berakhir pada 0).
Dan itu tidak membangun kembali seluruh nomor terbalik, hanya setengah.
Itu yang kita butuhkan.

(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

Solusi rekursif dalam ruby, tanpa mengubah angka menjadi 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

Versi 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

Lepaskan angka pertama dan terakhir dan bandingkan sampai Anda kehabisan. Mungkin ada digit yang tersisa, atau tidak, tetapi bagaimanapun juga, jika semua angka yang muncul cocok, itu adalah palindrom.


2

Berikut adalah satu lagi solusi dalam c ++ menggunakan templat. Solusi ini akan berfungsi untuk perbandingan string palindrom case-insensitive.

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

metode dengan faktor konstan yang sedikit lebih baik daripada metode @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

inilah versi # af:

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

Angka adalah palindromik jika representasi stringnya adalah palindromik:

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

Untuk memeriksa nomor yang diberikan adalah Palindrome atau tidak (Kode 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

Banyak solusi yang diposting di sini membalikkan bilangan bulat dan menyimpannya dalam variabel yang menggunakan ruang ekstra O(n), tetapi di sini adalah solusi dengan O(1)ruang.

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

Saya selalu menggunakan solusi python ini karena kekompakannya.

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

4
Itu kompak, tetapi OP secara khusus mengatakan " kecuali algoritma membuat angka menjadi string dan kemudian membalikkan string "
Edward

0

Coba ini:

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

Berikut ini adalah daftar solusi usings sebagai tumpukan dalam 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

muncul tumpukan hanya mempertimbangkan sisi paling kanan dari angka untuk perbandingan dan gagal cepat untuk mengurangi cek


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

Solusi buruk, buruk. Log10 adalah operasi floating-point yang sangat lambat. Jangan gunakan ini.
Rok Kralj

0

Cara rekursif, tidak terlalu efisien, hanya memberikan opsi

(Kode 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) 
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.