Як перевірити, чи є число паліндром?


127

Як перевірити, чи є число паліндром?

Будь-яка мова. Будь-який алгоритм. (за винятком алгоритму створення числа рядком та реверсування рядка).


5
Чи можете ви дізнатися розмір цілого числа в бітах? якщо так, скажіть A - це ні, а s - розмір B = A << s / 2, перевірте, чи A&B == 2 ^ s-1 - 2 ^ (s / 2) + 1
Nitin Garg

10
Що поганого в тому, щоб "зробити число рядком, а потім повернути рядок"?
Полковник Паніка

Почнемо з визначення того, що numberі що is a palindromeозначатиме в цьому контексті: як щодо 13E31 (основна десятка)? 01210 (ведучий нуль)? + 10-10 + 1 (п’ятьзначний збалансований трійковий)?
сіра борода

Відповіді:


128

Це одна з проблем проекту Euler . Коли я вирішив це в Haskell, я зробив саме те, що ви запропонували, перетворив число в String. Потім тривіально перевірити, чи є рядок палліндром. Якщо він працює досить добре, то навіщо турбуватись зробити його складнішим? Бути палліндромом - це лексична властивість, а не математична.


14
Справді. Будь-який алгоритм, який ви створюєте, повинен буде принаймні розділити число на базові 10 цифр, що на 90% перетворюється на рядок.
Blorgbeard вийшов

5
Це, безумовно, акуратний трюк, щоб перетворити його на рядок, але це начебто перемагає точку, якщо вас про це попросили на інтерв'ю, оскільки справа мала б визначити, чи розумієте ви модуль.
Роберт Ноак

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).
сіра борода

@greybeard - Я припускаю, що арифметика робиться на типі, який підтримує арифметику, а рядкові операції виконуються на типі, який підтримує рядкові операції - це поділ і модуль / залишок для цілих чи попередніх символів для рядка. Звичайно, ви можете реалізувати арифметику на рядках для себе, але (1) ви дійсно збираєтесь? Просто для перетворення цілого числа в рядок ?, і (2), хоча ви можете це впоратися (неефективно) без нього, вам потрібно буде зрозуміти залишки в якийсь момент - у вас немає повної цілої арифметики на рядках без цього.
Стів314

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
Естебан Арая

Це припущення, що обороти ініціалізовані до нуля?
Justsalt

Так, Джассальт. Змінна обороту ініціалізується до нуля.
Хорхе Феррейра

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

Працює лише для цілих чисел. З постановки проблеми незрозуміло, чи потрібно враховувати числа з плаваючою комою або провідні нулі.


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

Натисніть кожну окрему цифру на стек, а потім висуньте їх. Якщо це однаково вперед і назад, це паліндром.


Як виштовхуєте кожну окрему цифру від цілого числа?
Естебан Арая

1
Щось уздовж рядків: int firstDigit = originalNumber% 10; int tmpNumber = originalNumber / 10; int secondDigit = tmpNumber% 10; .... поки ти не закінчиш.
Грант Лімберг

Це не спрацює в контексті питання LeetCode - не допускається додаткове місце.
голограма

8

Я не помітив жодних відповідей, які вирішили цю проблему, не використовуючи додаткового місця, тобто всі рішення, які я бачив, або використовували рядок, або інше ціле число для зворотного перетворення числа, або деякі інші структури даних.

Хоча такі мови, як Java, перетворюються на цілі переповнення, ця поведінка є невизначеною для таких мов, як C. ( Спробуйте змінити 2147483647 (Integer.MAX_VALUE) на Java ). Обхідним способом
можна було б користуватися довгим чи іншим, але, стилістично, я не дуже подібний підхід.

Тепер концепція паліндромного числа полягає в тому, що число повинно читати однакові вперед і назад. Чудово. Використовуючи цю інформацію, ми можемо порівняти першу і останню цифру. Трюк - для першої цифри нам потрібен порядок числа. Скажімо, 12321. Поділивши це на 10000, ми зробимо нас лідируючими 1. Трейлінг 1 можна отримати, взявши мод з 10. Тепер, щоб зменшити це до 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;
}

Відредаговано згідно з пропозицією Хардіка , щоб охопити випадки, коли в нулі є нулі.


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)

Це також запобігає виникненню проблем із пам'яттю при рекурсії (наприклад, помилка StackOverflow в Java)


Близько, але ви мутуєте 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 (десятковий) - це "десятковий паліндром"? Неймовірно швидко і схоже на відповідь еку .
сіра борода

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 лозунг "струнні операції повільніші за арифметичні" насправді помилковий. Я порівняв арифметичний алгоритм Смінка з простим переворотом рядків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

Я відповів на проблему Ейлера дуже брутально. Звичайно, на дисплеї з'явився набагато розумніший алгоритм, коли я дістався до нової розблокованої асоційованої теми форуму. А саме, член, який пішов за ручку Бегонера, мав такий новий підхід, що я вирішив повторно реалізувати своє рішення, використовуючи його алгоритм. Його версія була в 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
Я спробував деякі "математичні" тести на паліндром, розміщені тут, але був здивований, що ця версія на основі рядків була швидшою.
Кріс Вест

Можливо, це не повинно дивувати - адже найшвидший спосіб, коли ви могли зрозуміти число, яке вам було дано, був паліндром, читаючи першу половину, потім читаючи другу половину назад, а не виконуючи арифметику
Зубін Мукерджі,

4

Ось версія схеми, яка будує функцію, яка буде працювати проти будь-якої бази. Він має перевірку надмірності: швидко повертайте помилкове значення, якщо число кратне базі (закінчується 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

Версія 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

Для перевірки вказаного числа є Palindrome чи ні (код 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

Я завжди використовую це рішення пітона через його компактність.

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

Ось таке рішення використовує списки як стеки в 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) 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.