숫자가 회문인지 어떻게 확인합니까?


127

숫자가 회문인지 어떻게 확인합니까?

모든 언어. 모든 알고리즘. (숫자를 문자열로 만든 다음 문자열을 되 돌리는 알고리즘 제외).


5
비트 단위의 정수 크기를 알 수 있습니까? 그렇다면, 말하는이며 아니요 및 S 사이즈 B = A << S / 2 [A & B == 2 ^는 S-1이면 - ^ (S / 2) + 1 2
니틴 Garg를

10
'숫자를 문자열로 만든 다음 문자열을 뒤집는'문제가 있습니까?
대령 패닉

무엇을 정의하여 시작 numberis a palindrome방법 13E31에 대한 (기본 열을) :이 상황에서 의미한다? 01210 (제로 0)? + 10-10 + 1 (5 자리 균형 삼항)?
greybeard

답변:


128

이것은 프로젝트 오일러 문제 중 하나입니다 . Haskell에서 해결했을 때 정확히 제안한대로 숫자를 문자열로 변환하십시오. 문자열이 pallindrome인지 확인하는 것은 사소한 일입니다. 성능이 충분하다면 왜 더 복잡하게 만드는가? pallindrome이된다는 것은 수학적인 것이 아니라 어휘 적 속성입니다.


14
과연. 모든 알고리즘은 적어도 숫자를 10 자릿수로 나누어야합니다. 어쨌든 문자열로 90 % 변환됩니다.
Blorgbeard는 08:10

5
그것은 분명히 문자열로 변환하는 깔끔한 트릭이지만 인터뷰 에서이 질문을 받으면 요점을 이길 수 있습니다. 왜냐하면 요점은 모듈로를 이해하는지 결정하는 것이기 때문입니다.
Robert Noack

7
@Robert Noack-면접관은 정수를 문자열로 변환하는 알고리즘을 설명하도록 요청할 수 있습니다. 물론 모듈로를 이해해야합니다.
Steve314

@ Steve314- to describe an algorithm to convert an integer to a string, which of course requires you to understand modulo아뇨. 당신이 일반적 이진 진수로 변환하는 방법을 생각하는 (할 것입니다 추가 할 수있는 대상 번호 시스템에서 계산하는 것은 - 생각하는 데 사용되는 계산 수단 바이너리 , 당신이 할 수없는 것은 예를 들면,하지 않는 소수 연산 (당신은 할 수 할 나누기 또는 모듈로없이 2 진수에서 10 진수로 변환 2)
greybeard

@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가 0으로 초기화되었다고 가정합니까?
Justsalt

그렇습니다 Justsalt. rev 변수는 0으로 초기화됩니다.
Jorge Ferreira

31
행인에 대한 참고 사항 :num 나누기 후의 부분을 ​​유지하는 언어로 언어를 구현하는 경우 (루터 타이핑) 그렇게해야합니다 num = floor(num / 10).
Wiseguy

22
이 솔루션은 완전히 맞지 않습니다. 변수 발굴이 넘칠 수 있습니다. 예를 들어, num 유형이 int이고 값이 거의 Integer.Max이고 마지막 숫자가 789 인 경우, 리버스 발굴을 수행 한 다음 오버플로합니다.
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!")

정수에만 작동합니다. 부동 소수점 숫자 또는 선행 0을 고려해야하는지 여부는 문제 설명에서 명확하지 않습니다.


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

숫자가 0이면 실패합니다. 예 : 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; .... 끝날 때까지.
Grant Limberg

LeetCode 질문과 관련하여 작동하지 않으므로 추가 공간이 허용되지 않습니다.
홀로그램

8

여분의 공간을 사용하지 않고이 문제를 해결 한 답변을 보지 못했습니다. 즉, 문자열이나 다른 정수를 사용하여 숫자를 바꾸거나 다른 데이터 구조를 사용하는 모든 솔루션을 보았습니다.

자바와 같은 언어는 정수 오버 플로우에 랩 어라운드 있지만,이 동작은 C. 같은 언어 (에 정의되지 자바 2147483647 (는 Integer.MAX_VALUE를) 반전 시도 )
해결 방법 문체, 꽤하지 않습니다, 긴 또는 무언가를 사용할 수 있지만, 할 수있다 그 접근법처럼.

회문 숫자의 개념은 숫자가 앞뒤로 동일하게 읽혀 져야한다는 것입니다. 큰. 이 정보를 사용하여 첫 번째 숫자와 마지막 숫자를 비교할 수 있습니다. 트릭은 첫 번째 숫자의 경우 순서가 필요합니다. 이것을 12321이라고 말하십시오. 이것을 10000으로 나누면 1을 얻을 수 있습니다. 후행 1은 10으로 mod를 가져 와서 검색 할 수 있습니다. 이제 이것을 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;
}

숫자가 0 인 경우를 다루기 위해 Hardik 의 제안에 따라 편집했습니다 .


6

파이썬에는 빠르고 반복적 인 방법이 있습니다.

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 (10 진수)은 "10 진수 회문"입니까? 믿을 수 없을 정도로 빠르며 eku의 답변 과 비슷합니다 .
greybeard

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십진 회문 인지 묻는다면 십진법으로 그것을 작성하여 테스트해야합니다.

파이썬에서 적어도 '문자열 연산이 산술보다 느리다'라는 슬로건은 실제로 거짓입니다. 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
여기에 게시 된 "수학적"회문 테스트를 시도했지만이 문자열 기반 버전이 더 빠르다는 것에 놀랐습니다.
Chris Vest

어쩌면 이것은 놀라운 일이 아닙니다. 결국 여러분이 회문이라는 것을 깨달을 수있는 가장 빠른 방법은 모든 종류의 산술이 아닌 상반기를 읽은 다음 후반을 거꾸로 읽는 것입니다.
Zubin Mukerjee

4

다음은 모든 기본에 대해 작동하는 함수를 구성하는 구성표 버전입니다. 중복 검사 기능이 있습니다. 숫자가 기수의 배수이면 신속하게 false를 반환합니다 (0으로 끝남).
그리고 전체 역수를 다시 만들지 않고 절반 만 만듭니다.
그게 우리가 필요한 전부입니다.

(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

골랑 버전 :

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

문자열 표현이 palindromic 인 경우 숫자는 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

주어진 숫자가 Palindrome인지 아닌지 확인하려면 (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");
    }
}

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

나는 컴팩트하기 때문에 항상이 파이썬 솔루션을 사용합니다.

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

4
즉 소형이지만, 영업 이익은 특히 "며 문자열을 반전 한 후 숫자를 문자열을 만드는 및 알고리즘 제외 "
에드워드

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

다음은 파이썬에서 목록을 스택으로 사용하는 솔루션입니다.

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

0

매우 효율적이지 않은 재귀 방식은 옵션을 제공합니다.

(파이썬 코드)

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) 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.