我如何检查数字是否是回文?


127

我如何检查数字是否是回文?

任何语言。任何算法。(使数字成为字符串然后反转字符串的算法除外)。


5
您能找出整数的大小(以位为单位)吗?如果是,则说A为否,并且s为大小B = A << s / 2检查A&B == 2 ^ s-1-2 ^(s / 2)+ 1
Nitin Garg

10
“将数字制成字符串然后反转字符串”有什么问题?
Panic Panic

首先定义什么numberis a palindrome在上下文中表示什么:13E31(以10为底)怎么样?01210(前导零)?+ 10-10 + 1(五位数平衡三进制)?
灰胡子2014年

Answers:


128

这是欧拉计划的问题之一。当我在Haskell中解决该问题时,我完全按照您的建议做了,将数字转换为String。然后,检查该字符串是否为pallindrome变得很简单。如果它的性能足够好,那为什么还要麻烦使其更复杂呢?作为一个综合症是一种词汇性质,而不是一种数学性质。


14
确实。您执行的任何算法都必须至少将数字分成10个基数的数字,无论如何,该数字将90%转换为字符串。
Blorgbeard将于

5
将其转换为字符串绝对是一种巧妙的技巧,但是如果在面试中被问到这一点,那是有点不对劲,因为要点是确定您是否理解模数。
罗伯特·诺亚克

7
@Robert Noack-面试官可以要求您描述一种将整数转换为字符串的算法,这当然需要您理解模数。
Steve314 2013年

@ Steve314- to describe an algorithm to convert an integer to a string, which of course requires you to understand modulo不 计算目标数字系统,能够增加会做(想想你如何从常用的十进制转换为二进制-用来思考的计算方法二进制并不意味着你不能这样做,例如,十进制算法(你可以做从二进制到十进制的转换,不进行除法或取模2)
灰胡子

@greybeard-我假设算术是在支持算术的类型上完成的,而字符串操作是在支持字符串操作的类型上进行的-这是整数的除法和模/余数,字符串的前置字符。当然,您可以自己对字符串执行算术运算,但是(1)您真的要这么做吗?只是要将整数转换为字符串?,并且(2)尽管没有它也可以(效率低下)地处理它,但您仍需要在某些时候了解余数-如果没有整数,您将无法对字符串进行完整的算术运算。
Steve314

269

对于任何给定的数字:

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

如果n == rev然后num是回文:

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

那也是我想起的。我想我现在发布它毫无意义。+1
Esteban Araya

这是否假设rev初始化为零?
Justsalt

是的Justsalt。rev变量被初始化为零。
豪尔赫·费雷拉

31
给过路人的注意事项:如果以能保留numafter除法(较弱的键入)的分数的语言来实现,则需要这样做num = floor(num / 10)
Wiseguy

22
这种解决方案并不完全正确。变量挖掘可能会溢出。例如,我假设num的类型是int,值几乎是Integer.Max,它的最后一位是789,当反向挖掘时,然后溢出。
李佳吉

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!")

仅适用于整数。从问题陈述中不清楚,是否需要考虑浮点数或前导零。


22

在大多数答案中,有一个琐碎的问题是int变量可能会溢出。

请参阅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;
}

当数字为零时将失败。例如: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

将每个数字推入堆栈,然后将其弹出。如果前后是相同的,那就是回文。


如何将整数中的每个数字都压入?
Esteban Araya

1
类似于以下内容:int firstDigit = originalNumber%10; int tmpNumber = originalNumber / 10; int secondDigit = tmpNumber%10; ....直到完成。
格兰特·林伯格

这在LeetCode问题的上下文中不起作用-不允许有额外的空间。
全息图

8

我没有注意到有没有使用任何额外空间来解决此问题的答案,即,我看到的所有解决方案都使用字符串或另一个整数来反转数字或其他一些数据结构。

尽管Java之类的语言会在整数溢出时回绕,但是C之类的语言中未定义此行为。(尝试在Java中反转2147483647(Integer.MAX_VALUE)
解决方法可能是使用long或类似方法,但从风格上讲,我不太喜欢那种方法。

现在,回文数的概念是该数应前后读相同。大。使用此信息,我们可以比较第一位数字和最后一位数字。技巧是,对于第一个数字,我们需要数字的顺序。比方说12321。将其除以10000将得到前导1。可以通过将mod取值为10来检索尾随的1。现在,将其减少到232 (12321 % 10000)/10 = (2321)/10 = 232。现在,需要将10000减少2倍。因此,现在进入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;
}

根据Hardik的建议进行编辑,以涵盖数字为零的情况。


6

在Python中,有一种快速的迭代方法。

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

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

这也可以防止内存出现递归问题(例如Java中的StackOverflow错误)


关闭,但是您要在执行此操作时使n突变。您要存储原始n值,并使用该值进行返回比较
RGroppa

6

我知道的最快方法:

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(十进制)是“十进制回文”吗?快得惊人,类似于eku的回答
灰胡子

5

只是为了好玩,这个也可以。

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

除了将数字设为字符串,然后反转字符串。

为什么要取消该解决方案?它易于实现且易于阅读。如果在没有手头电脑的情况下询问您是否2**10-23是十进制回文,则可以通过将其写成十进制来进行测试。

至少在Python中,口号“字符串操作比算术慢”实际上是错误的。我将Smink的算术算法与简单的字符串反转进行了比较int(str(i)[::-1])。速度没有显着差异-发生字符串反转的速度略快。

在编译语言(C / C ++)中,该口号可能成立,但其中一个风险就是大量溢出错误。

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)

结果以秒为单位(越低越好):

串入1.50960231881算术1.69729960569


4

我用一种蛮横的方式回答了欧拉问题。自然,当我进入新的未锁定的相关论坛主题时,会显示出更智能的算法。即,一个由Begoner操纵的成员使用了一种新颖的方法,以至于我决定使用他的算法重新实现我的解决方案。他的版本是Python(使用嵌套循环),而我在Clojure中重新实现了(使用单个循环/递归)。

在这里为您娱乐:

(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的答案,但对我来说这些答案是不可理解的。


1
我尝试了此处发布的一些“数学”回文测验,但惊讶于此基于字符串的版本更快。
克里斯·韦斯特

也许这并不令人惊讶-毕竟,您可以最快地意识到分配给您的数字是回文,那就是先阅读上半部分然后向后阅读下半部分,而不用做任何算术
Zubin Mukerjee

4

这是一个Scheme版本,该版本构造了可以针对任何基础工作的函数。它具有冗余检查:如果该数字是底数的倍数(以0结尾),则快速返回false。
而且它不会重建整个倒数,只有一半。
这就是我们所需要的。

(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

红宝石的递归解决方案,无需将数字转换为字符串。

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版本:

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

弹出第一个和最后一个数字并进行比较,直到用完为止。可能还剩下一个数字,但是无论哪种方式,如果所有弹出的数字都匹配,那就是回文。


2

这是使用模板的c ++中的另一种解决方案。该解决方案适用于不区分大小写的回文字符串比较。

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方法好一点的方法:

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

这是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

如果数字的字符串表示形式为回文,则为回文:

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

要检查给定的编号是否为回文式(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

此处发布的许多解决方案都将整数取反,并将其存储在使用额外空间的变量中,该变量为O(n),但这是带O(1)空间的解决方案。

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

由于其紧凑性,我一直使用此python解决方案。

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

4
那很紧凑,但是OP专门说“ 除了将数字变成字符串然后反转字符串的算法外
Edward

0

试试这个:

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

这是使用列表作为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

弹出堆栈仅考虑数字的最右边进行比较,并且无法快速减少检查次数


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

糟糕,糟糕的解决方案。Log10是一个非常缓慢的浮点运算。不要使用这个。
Rok Kralj 2015年

0

递归的方式,不是很有效,只是提供一个选择

(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) 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.