ฉันจะตรวจสอบได้อย่างไรว่าตัวเลขนั้นเป็นพาลินโดรม?


127

ฉันจะตรวจสอบได้อย่างไรว่าตัวเลขนั้นเป็นพาลินโดรม?

ภาษาใดก็ได้ อัลกอริทึมใด ๆ (ยกเว้นอัลกอริทึมในการทำให้ตัวเลขเป็นสตริงแล้วย้อนกลับสตริง)


5
คุณสามารถหาขนาดของจำนวนเต็มเป็นบิตได้หรือไม่? ถ้าใช่ให้บอกว่า A คือไม่ใช่และ s คือขนาด B = A << s / 2 ตรวจสอบว่า A&B == 2 ^ s-1 - 2 ^ (s / 2) + 1
Nitin Garg

10
เกิดอะไรขึ้นกับการ 'ทำให้ตัวเลขเป็นสตริงแล้วย้อนกลับสตริง'
พันเอก Panic

เริ่มต้นด้วยการกำหนดสิ่งที่numberและis a palindromeจะหมายถึงในบริบทนี้: แล้ว 13E31 (ฐานสิบ) ล่ะ? 01210 (ศูนย์นำหน้า)? + 10-10 + 1 (สมดุลห้าหลัก)?
greybeard

คำตอบ:


128

นี้เป็นหนึ่งในปัญหาที่โครงการออยเลอร์ เมื่อฉันแก้ไขมันใน Haskell ฉันได้ทำตามที่คุณแนะนำแล้วให้แปลงตัวเลขเป็น String เป็นเรื่องเล็กน้อยที่จะต้องตรวจสอบว่าสตริงเป็นแพลลินโดรม ถ้ามันทำงานได้ดีพอทำไมต้องทำให้ซับซ้อนมากขึ้น? การเป็นแพลลินโดรมเป็นคุณสมบัติของคำศัพท์มากกว่าคุณสมบัติทางคณิตศาสตร์


14
จริง อัลกอริทึมใด ๆ ที่คุณทำจะต้องแบ่งตัวเลขออกเป็นหลัก 10 หลักเป็นอย่างน้อยซึ่ง 90% จะถูกแปลงเป็นสตริงอยู่ดี
Blorgbeard ออกใน

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)
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เป็น palindrome:

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

นั่นคือสิ่งที่ฉันคิดขึ้นมาด้วย ฉันเดาว่าฉันโพสต์มันตอนนี้ไม่มีเหตุผล +1
Esteban Araya

นี่สมมติว่า rev เริ่มต้นเป็นศูนย์หรือไม่?
Justsalt

ใช่ Justsalt ตัวแปร rev เริ่มต้นเป็นศูนย์
Jorge Ferreira

31
หมายเหตุสำหรับผู้สัญจร:หากใช้สิ่งนี้ในภาษาที่จะเก็บส่วนที่เป็นเศษส่วนของnumหลังการหาร (การพิมพ์แบบหลวม ๆ ) คุณจะต้องทำnum = floor(num / 10)เช่นนั้น
Wiseguy

22
วิธีนี้ไม่ถูกต้องทั้งหมด การขุดตัวแปรอาจจะล้น ตัวอย่างเช่นฉันถือว่าประเภทของ num คือ int ค่าเกือบจะเป็นจำนวนเต็มค่าสูงสุดหลักสุดท้ายคือ 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


9

ดันตัวเลขแต่ละตัวลงในสแต็กจากนั้นดึงออก ถ้าข้างหน้าและข้างหลังเหมือนกันแสดงว่าเป็นพาลินโดรม


คุณดันแต่ละหลักจากจำนวนเต็มได้อย่างไร?
Esteban Araya

1
บางสิ่งตามบรรทัดของ: int firstDigit = originalNumber% 10; int tmpNumber = originalNumber / 10; int secondDigit = tmpNumber% 10; .... จนกว่าคุณจะทำเสร็จ
Grant Limberg

สิ่งนี้จะใช้ไม่ได้ในบริบทของคำถาม LeetCode - ไม่อนุญาตให้มีพื้นที่เพิ่มเติม
โฮโลแกรม

8

ฉันไม่สังเกตเห็นคำตอบใด ๆ ที่แก้ไขปัญหานี้โดยไม่ใช้ช่องว่างเพิ่มเติมนั่นคือวิธีแก้ปัญหาทั้งหมดที่ฉันเห็นอาจใช้สตริงหรือจำนวนเต็มอื่นเพื่อย้อนกลับตัวเลขหรือโครงสร้างข้อมูลอื่น ๆ

แม้ว่าภาษาเช่น Java จะล้อมรอบด้วยจำนวนเต็มล้น แต่พฤติกรรมนี้ไม่ได้กำหนดไว้ในภาษาเช่น C. ( ลองย้อนกลับ 2147483647 (Integer.MAX_VALUE) ใน Java )
วิธีแก้ปัญหาคือใช้ long หรือบางอย่าง แต่ในทางโวหารฉันไม่ค่อย ชอบแนวทางนั้น

ตอนนี้แนวคิดของเลขพาลินโดรมิกคือจำนวนควรอ่านไปข้างหน้าและข้างหลังเหมือนกัน ยิ่งใหญ่ เมื่อใช้ข้อมูลนี้เราสามารถเปรียบเทียบตัวเลขหลักแรกและหลักสุดท้าย เคล็ดลับคือสำหรับหลักแรกเราต้องการลำดับของตัวเลข กล่าวว่า 12321. แบ่งนี้โดย 10000 จะได้รับเรา 1. ชั้นนำต่อท้าย 1 สามารถเรียกดูได้โดยการ mod กับ 10 ตอนนี้เพื่อลดนี้ (12321 % 10000)/10 = (2321)/10 = 232232 และตอนนี้ 10,000 จะต้องลดลงด้วยปัจจัย 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)

นอกจากนี้ยังป้องกันปัญหาหน่วยความจำเกี่ยวกับการเรียกซ้ำ (เช่นข้อผิดพลาด 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 (ทศนิยม) คือ "ฐานสิบหก"? ไม่น่าเชื่ออย่างรวดเร็วและคล้ายกับคำตอบของ 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เป็นพาลินโดรมทศนิยมหรือไม่คุณก็ต้องทดสอบด้วยการเขียนเป็นทศนิยม

อย่างน้อยที่สุดใน 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 (โดยใช้ single loop / ซ้ำ)

ที่นี่เพื่อความบันเทิงของคุณ:

(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)))

มีคำตอบ Lisp ทั่วไปเช่นกัน แต่พวกเขาไม่พอใจสำหรับฉัน


1
ฉันลองทดสอบ palindrome "ทางคณิตศาสตร์" บางรายการที่โพสต์ไว้ที่นี่ แต่รู้สึกแปลกใจที่เวอร์ชันที่ใช้สตริงนี้เร็วกว่า
Chris Vest

อาจจะไม่น่าแปลกใจเพราะวิธีที่เร็วที่สุดที่คุณจะรู้ได้ว่าตัวเลขที่มอบให้กับคุณคือพาลินโดรมคือการอ่านครึ่งแรกจากนั้นอ่านครึ่งหลังไปข้างหลังไม่ใช่ด้วยการทำเลขคณิตใด ๆ
Zubin Mukerjee

4

นี่คือเวอร์ชัน Scheme ที่สร้างฟังก์ชันที่จะทำงานร่วมกับฐานใด ๆ มีการตรวจสอบความซ้ำซ้อน: ส่งคืนเท็จอย่างรวดเร็วหากตัวเลขเป็นผลคูณของฐาน (ลงท้ายด้วย 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 ++ โดยใช้เทมเพลต โซลูชันนี้จะใช้ได้กับการเปรียบเทียบสตริง palindrome แบบตัวพิมพ์เล็กและใหญ่

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

เพื่อตรวจสอบหมายเลขที่ระบุว่าเป็น 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

ฉันใช้โซลูชัน 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

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.