番号が回文かどうかを確認するにはどうすればよいですか?


127

番号が回文かどうかを確認するにはどうすればよいですか?

どんな言語でも。任意のアルゴリズム。(数値を文字列にしてから文字列を逆にするアルゴリズムを除く)。


5
整数のサイズをビット単位で確認できますか?はいの場合、Aはノーで、sはサイズB = A << s / 2であるかどうかを確認A&B == 2 ^ s-1-2 ^(s / 2)+ 1かどうかを確認
Nitin Garg

10
「数値を文字列にしてから文字列を逆にする」の何が問題になっていますか?
、パニック大佐

このコンテキストで何numberis a palindrome意味し、何を意味するかから開始します。13E31(10進法)はどうですか?01210(先行ゼロ)?+ 10-10 + 1(5桁のバランスの取れた3値)?
greybeard 2014

回答:


128

これは、プロジェクトオイラー問題の1つです。私がHaskellでそれを解決したとき、あなたが提案したとおりに、数値を文字列に変換しました。次に、文字列が回文であることを確認するのは簡単です。それが十分に機能する場合、なぜわざわざ複雑にするのですか?回文であることは、数学的なものではなく、語彙的な特性です。


14
確かに。作成するアルゴリズムでは、少なくとも数値を10進数に分割する必要があります。これは、とにかく文字列に90%変換されます。
Blorgbeardは

5
それを文字列に変換することは間違いなくきちんとしたトリックですが、インタビューでこれを尋ねられた場合、モジュロを理解しているかどうかを判断することがポイントになるので、ポイントを打ち負かします。
Robert Noack 2013年

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いいえ。考えるために使用されている-あなたは、一般的に10進数からバイナリに変換する方法を考える(、目標数のシステムで計算を追加することができることでしょうバイナリ計算手段あなたが行うことができないという意味ではありませんが、例えば、10進法計算(とあなたがすることができません除算または2を法としない2進数から10進数への変換)
greybeard

@greybeard-算術は算術をサポートするタイプで行われ、文字列操作は文字列操作をサポートするタイプで行われると仮定しています-これは除算と整数の剰余/剰余であり、文字列の先頭に文字を追加します。もちろん、あなたがすることができ、自分自身のための文字列を算術実装しますが、(1)あなたは本当にするつもりですか?整数を文字列に変換するだけですか?(2)これなしでこれを(非効率的に)処理できますが、ある時点で剰余を理解する必要があります。これがないと、文字列の完全な整数演算ができません。
Steve314 2016年

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
エステバンアラヤ

これは、revがゼロに初期化されていることを前提としていますか?
Justsalt 2008年

はいJustsalt。rev変数はゼロに初期化されます。
ホルヘフェレイラ

31
通行人への注意:num除算後の小数部分を維持する言語でこれを実装する場合(タイピングを緩める)、それを行う必要がありますnum = floor(num / 10)
Wiseguy

22
このソリューションは完全に正しくありません。変数digがオーバーフローする可能性があります。たとえば、numの型がintで、値がほぼInteger.Maxであると想定します。最後の桁は789で、リバースディグするとオーバーフローします。
Jiaji Li 2013

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; ....完了するまで。
Grant Limberg、

これはLeetCode質問のコンテキストでは機能しません-追加のスペースは許可されません。
ホログラム

8

余分なスペースを使用せずにこの問題を解決した答えに気付きませんでした。つまり、私が見たすべてのソリューションは、文字列または別の整数を使用して数値を反転したり、その他のデータ構造を使用していました。

Javaのような言語は、整数オーバーフローの上にラップアラウンドが、この動作はC.のような言語(で定義されていないJavaで2147483647(Integer.MAX_VALUEの)を反転してください
回避策は、文体、私はかなりない、長いか何かを使用することだけに可能性そのアプローチのように。

現在、回文番号の概念は、その番号を同じように前方と後方に読む必要があるということです。すごい。この情報を使用して、最初の桁と最後の桁を比較できます。トリックは、最初の桁のために、私たちは数の順序が必要です。12321と言います。これを10000で割ると、先頭が1になります。末尾の1は、modを10にすると取得できます(12321 % 10000)/10 = (2321)/10 = 232。これを232に減らします。そして今、10000を2分の1に減らす必要があります。それでは、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(decimal)は「decimal palindrome」ですか?信じられないほど高速で、ekuの回答に似ています
greybeard 2016年

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-2310進数のパリンドロームであるかどうかを手元にないコンピューターで尋ねられた場合は、10進数で書き出すことで確実にテストします。

少なくともPythonでは、「文字列操作は算術よりも遅い」というスローガンは実際には誤りです。スミンクの算術アルゴリズムを単純な文字列反転と比較しました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

これは、どのベースに対しても機能する関数を構築する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

数値を文字列に変換せずに、rubyで再帰的に解決します。

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 ++のもう1つのソリューションを次に示します。このソリューションは、大文字と小文字を区別しない回文の文字列比較で機能します。

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は、具体的には、「言った数に文字列を作成して、文字列を逆転させるアルゴリズムを除いて
エドワード

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

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) 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.