Làm thế nào để tôi kiểm tra nếu một số là một palindrom?


127

Làm thế nào để tôi kiểm tra nếu một số là một palindrom?

Bất kỳ ngôn ngữ. Bất kỳ thuật toán. (ngoại trừ thuật toán tạo số thành chuỗi và sau đó đảo ngược chuỗi).


5
Bạn có thể tìm ra kích thước của số nguyên theo bit? nếu có, Nói A là số không và s là kích thước B = A << s / 2 kiểm tra xem A & B == 2 ^ s-1 - 2 ^ (s / 2) + 1
Nitin Garg

10
Có gì sai với 'làm cho số thành một chuỗi và sau đó đảo ngược chuỗi'?
Đại tá hoảng loạn

Bắt đầu bằng cách xác định những gì numberis a palindromesẽ có nghĩa trong bối cảnh này: làm thế nào về 13E31 (cơ sở mười)? 01210 (số 0 đứng đầu)? + 10-10 + 1 (năm chữ số cân bằng)?
greybeard

Câu trả lời:


128

Đây là một trong những vấn đề của Project Euler . Khi tôi giải quyết nó trong Haskell, tôi đã làm chính xác những gì bạn đề xuất, chuyển đổi số thành Chuỗi. Sau đó, thật đơn giản để kiểm tra xem chuỗi có phải là một pallindrom không. Nếu nó thực hiện đủ tốt, thì tại sao phải làm cho nó phức tạp hơn? Trở thành một pallindrom là một thuộc tính từ vựng chứ không phải là một toán học.


14
Thật. Bất kỳ thuật toán nào bạn thực hiện sẽ ít nhất phải chia số thành 10 chữ số cơ bản, được chuyển đổi 90% thành một chuỗi.
Blorgbeard ra mắt vào

5
Đây chắc chắn là một mẹo gọn gàng để chuyển đổi nó thành một chuỗi nhưng nó sẽ đánh bại điểm nếu bạn được hỏi điều này trong một cuộc phỏng vấn bởi vì vấn đề sẽ là xác định xem bạn có hiểu modulo không.
Robert Noack

7
@Robert Noack - người phỏng vấn sau đó có thể yêu cầu bạn mô tả một thuật toán để chuyển đổi một số nguyên thành một chuỗi, tất nhiên điều này đòi hỏi bạn phải hiểu modulo.
Steve314 23/12/13

@ Steve314 to describe an algorithm to convert an integer to a string, which of course requires you to understand modulo- không. Tính toán trong hệ thống số mục tiêu, có thể thêm sẽ làm (nghĩ cách bạn thường chuyển đổi từ thập phân sang nhị phân - được sử dụng để nghĩ tính toán có nghĩa là nhị phân không có nghĩa là bạn không thể làm, ví dụ, số học thập phân (và bạn có thể làm chuyển đổi từ nhị phân sang thập phân mà không chia hoặc modulo 2).
greybeard

@greybeard - Tôi giả sử số học được thực hiện trên loại hỗ trợ số học và các thao tác chuỗi được thực hiện trên loại hỗ trợ các hoạt động chuỗi - đó là phép chia và modulo / phần còn lại cho số nguyên và ký tự chuẩn bị cho chuỗi. Tất nhiên bạn có thể thực hiện số học trên các chuỗi cho chính mình, nhưng (1) bạn có thực sự sẽ làm? Chỉ cần chuyển đổi một số nguyên thành một chuỗi?, Và (2) mặc dù bạn có thể xử lý việc này (không hiệu quả) mà không có nó, bạn sẽ cần phải hiểu phần còn lại tại một số điểm - bạn không có số học hoàn toàn về số học trên các chuỗi mà không có điều đó.
Steve314

269

Đối với bất kỳ số nào:

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

Nếu n == revsau đó numlà một palindrom:

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

đó là những gì tôi đã đưa ra w / quá. Tôi đoán không có ý nghĩa trong tôi gửi nó bây giờ. +1
Esteban Araya

Đây có phải là giả định rằng rev được khởi tạo về không?
Jowersalt

Có Jowersalt. Biến rev được khởi tạo bằng không.
Jorge Ferreira

31
Lưu ý cho người qua đường: nếu thực hiện điều này bằng ngôn ngữ sẽ giữ phần phân đoạn numsau khi phân chia (gõ lỏng hơn), bạn sẽ cần phải thực hiện điều đó num = floor(num / 10).
Wiseguy

22
Giải pháp này không hoàn toàn đúng. biến đào có thể có thể tràn. Ví dụ, tôi giả sử loại num là int, giá trị gần như Integer.Max, chữ số cuối cùng của nó là 789, khi đào ngược lại, sau đó tràn.
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!")

Chỉ hoạt động cho số nguyên. Không rõ ràng từ báo cáo vấn đề nếu số lượng dấu phẩy động hoặc số 0 đứng đầu cần được xem xét.


22

Trên hầu hết các câu trả lời có một vấn đề nhỏ là biến int có thể có thể bị tràn.

Tham khảo http://articles.leetcode.com/palindrom-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;
}

Sẽ thất bại khi số có số không trong đó. Ví dụ: 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

Đẩy từng chữ số riêng lẻ lên một chồng, sau đó bật chúng ra. Nếu nó giống nhau về phía trước và phía sau, thì đó là một bảng màu.


Làm thế nào để bạn đẩy từng chữ số riêng lẻ từ số nguyên?
Esteban Araya

1
Một cái gì đó dọc theo dòng: int firstDigit = originalNumber% 10; int tmpNumber = gốcNumber / 10; int secondDigit = tmpNumber% 10; .... cho đến khi bạn hoàn thành.
Cấp Limberg

Điều này sẽ không hoạt động trong bối cảnh câu hỏi LeetCode - không cho phép thêm không gian.
hình ba chiều

8

Tôi không nhận thấy bất kỳ câu trả lời nào giải quyết vấn đề này khi không sử dụng thêm dung lượng, tức là tất cả các giải pháp tôi thấy hoặc đã sử dụng một chuỗi hoặc một số nguyên khác để đảo ngược số hoặc một số cấu trúc dữ liệu khác.

Mặc dù các ngôn ngữ như Java bao quanh tràn số nguyên, hành vi này không được xác định trong các ngôn ngữ như C. ( Thử đảo ngược 2147483647 (Integer.MAX_VALUE) trong Java )
Cách khắc phục có thể là sử dụng lâu dài hoặc một cái gì đó, nhưng về mặt phong cách, tôi không hoàn toàn như cách tiếp cận đó

Bây giờ, khái niệm về một số palindromic là số nên đọc cùng một tiến và lùi. Tuyệt quá. Sử dụng thông tin này, chúng ta có thể so sánh chữ số đầu tiên và chữ số cuối cùng. Thủ thuật là, đối với chữ số đầu tiên, chúng ta cần thứ tự của số. Giả sử, 12321. Chia số này bằng 10000 sẽ giúp chúng ta dẫn đầu 1. Có thể lấy ra dấu 1 bằng cách lấy mod với 10. Bây giờ, để giảm số này xuống 232 (12321 % 10000)/10 = (2321)/10 = 232.. Và bây giờ, 10000 sẽ cần phải giảm đi 2 lần. Vì vậy, bây giờ với mã 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;
}

Được chỉnh sửa theo đề nghị của Hardik để bao gồm các trường hợp có số không trong số.


6

Trong Python, có một cách lặp lại nhanh chóng.

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

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

Điều này cũng ngăn ngừa các vấn đề về bộ nhớ với đệ quy (như lỗi StackOverflow trong Java)


Đóng, nhưng bạn đang biến đổi n trong khi làm điều này. Bạn muốn lưu trữ giá trị n ban đầu và thực hiện so sánh trả lại bằng cách sử dụng thay vào đó
RGroppa

6

Cách nhanh nhất tôi biết:

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 (thập phân) là "palindrom thập phân"? Không thể tin được nhanh chóng, và tương tự như câu trả lời của eku .
greybeard

5

Chỉ để cho vui, cái này cũng hoạt động.

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

ngoại trừ làm cho số một chuỗi và sau đó đảo ngược chuỗi.

Tại sao lại bỏ qua giải pháp đó? Thật dễ dàng để thực hiện và có thể đọc được . Nếu bạn được hỏi không có máy tính trong tay liệu2**10-23 là một bảng màu thập phân hay không, chắc chắn bạn sẽ kiểm tra nó bằng cách viết nó ra dưới dạng thập phân.

Trong Python ít nhất, khẩu hiệu 'hoạt động chuỗi chậm hơn số học' thực sự là sai. Tôi đã so sánh thuật toán số học của Smink với đảo ngược chuỗi đơn giảnint(str(i)[::-1]) . Không có sự khác biệt đáng kể về tốc độ - nó đã xảy ra đảo ngược chuỗi nhanh hơn một chút.

Trong các ngôn ngữ được biên dịch (C / C ++), khẩu hiệu có thể giữ, nhưng có một rủi ro tràn lỗi với số lượng lớn.

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)

Kết quả tính bằng giây (thấp hơn là tốt hơn):

strung 1.50960231881 số học 1.69729960569


4

Tôi đã trả lời vấn đề Euler bằng cách sử dụng một cách rất tàn bạo. Đương nhiên, có một thuật toán thông minh hơn được hiển thị khi tôi đến chủ đề diễn đàn liên quan đã mở khóa mới. Cụ thể, một thành viên đã xử lý Begoner có cách tiếp cận mới lạ như vậy, tôi quyết định thực hiện lại giải pháp của mình bằng thuật toán của mình. Phiên bản của anh ấy là Python (sử dụng các vòng lặp lồng nhau) và tôi đã thực hiện lại nó trong Clojure (sử dụng một vòng lặp / recur).

Ở đây để bạn giải trí:

(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ũng có câu trả lời Lisp chung, nhưng chúng không thể chấp nhận được đối với tôi.


1
Tôi đã thử một số bài kiểm tra palindrom "toán học" được đăng ở đây, nhưng thật ngạc nhiên khi phiên bản dựa trên chuỗi này là phiên bản nhanh hơn.
Chris Vest

Có lẽ điều này không có gì đáng ngạc nhiên - sau tất cả, cách nhanh nhất bạn có thể nhận ra một con số được trao cho bạn là một bảng màu là bằng cách đọc nửa đầu sau đó đọc nửa sau, không phải bằng bất kỳ loại số học nào
Zubin Mukerjee

4

Đây là một phiên bản Scheme xây dựng một chức năng sẽ hoạt động chống lại bất kỳ cơ sở nào. Nó có một kiểm tra dự phòng: trả về false một cách nhanh chóng nếu số đó là bội số của cơ sở (kết thúc bằng 0).
Và nó không xây dựng lại toàn bộ số đảo ngược, chỉ một nửa.
Đó là tất cả những gì chúng ta cần.

(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

Giải pháp đệ quy trong ruby, mà không chuyển đổi số thành chuỗi.

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

Phiên bản 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

Tắt các chữ số đầu tiên và cuối cùng và so sánh chúng cho đến khi bạn hết. Có thể có một chữ số còn lại hoặc không, nhưng một trong hai cách, nếu tất cả các chữ số bật ra khớp với nhau, đó là một bảng màu.


2

Đây là một giải pháp nữa trong c ++ bằng cách sử dụng các mẫu. Giải pháp này sẽ làm việc cho trường hợp so sánh chuỗi palindrom không nhạy.

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

một phương thức có hệ số hằng số tốt hơn một chút so với phương thức @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

Đây là phiên bản 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

Một số là palindromic nếu biểu diễn chuỗi của nó là palindromic:

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

Để kiểm tra số đã cho có phải là Palindrom hay không (Mã 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

Rất nhiều giải pháp được đăng ở đây đảo ngược số nguyên và lưu trữ nó trong một biến sử dụng thêm không gian O(n), nhưng đây là một giải pháp có O(1)không gian.

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

Tôi luôn luôn sử dụng giải pháp python này do sự nhỏ gọn của nó.

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

4
Đó là nhỏ gọn, nhưng OP đặc biệt nói " ngoại trừ thuật toán tạo số thành chuỗi và sau đó đảo ngược chuỗi "
Edward

0

Thử cái này:

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

Dưới đây là một giải pháp sử dụng danh sách như ngăn xếp trong 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

popping stack chỉ xem xét phía bên phải của số để so sánh và nó không nhanh chóng để giảm kiểm tra


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

Giải pháp xấu, xấu. Log10 là một hoạt động thực sự chậm, điểm nổi. Không sử dụng cái này.
Rok Kralj

0

Cách đệ quy, không hiệu quả lắm, chỉ cung cấp một tùy chọn

(Mã 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) 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.