นากกายกำลังย้ายบล็อกเรียงจากปลายหนึ่งไปอีกปลายพร้อมถาดกันล้น

LeetCode 7 Reverse Integer: กลับหลักพร้อมหยุดก่อนล้น 32-bit

พี่โชว์Engineering

โจทย์ Reverse Integer ให้กลับลำดับหลักของจำนวนเต็ม signed 32-bit และคืนศูนย์เมื่อผลลัพธ์อยู่นอกช่วงที่กำหนด ศูนย์นำหน้าหลังกลับจะหายตามค่าจำนวนเต็มครับ

สรุปโจทย์ด้วยคำของเรา

เก็บเครื่องหมายไว้ กลับเฉพาะหลักของค่าสัมบูรณ์ แล้วนำเครื่องหมายกลับมา จุดที่โจทย์วัดจริงคือ overflow: ภาษาอย่าง Python เก็บ integer ใหญ่ได้ จึงต้องตรวจขอบ 32-bit เอง ไม่ใช่ปล่อยให้ runtime บอก

วิธีที่ 1: แปลงเป็นข้อความ

แปลงค่าสัมบูรณ์เป็น string, reverse ด้วย slicing, parse กลับ และตรวจช่วง

  • เวลา O(d) เมื่อ d คือจำนวนหลัก
  • หน่วยความจำ O(d)
  • อ่านง่าย เหมาะกับ production utility หากโจทย์ไม่ห้าม string

วิธีที่ 2: pop หลักท้ายแล้ว push เข้าผลลัพธ์

ใช้ digit = value % 10, ลดค่าด้วย integer division และสร้าง reversed = reversed * 10 + digit วิธีนี้แสดงกลไกเลขฐานสิบตรง ๆ

  • เวลา O(d)
  • หน่วยความจำ O(1)
  • ในภาษาที่ integer ล้นได้ ต้องตรวจ ก่อน คูณและบวก; ใน Python ตัวอย่างตรวจผลทุกก้าวเพื่อจำลอง boundary เดียวกัน

วิธีที่ 3: เก็บหลักใน stack แล้วประกอบใหม่

แยกหลักทั้งหมดใส่ list ก่อนแล้ววนประกอบ เป็นภาพชัดแต่ใช้ O(d) memory โดยไม่ได้อ่านง่ายกว่า string มากนัก เหมาะเฉพาะเมื่อต้อง transform หลักระหว่างทาง

import unittest


LOWER = -(2**31)
UPPER = 2**31 - 1


def reverse_string(value):
    sign = -1 if value < 0 else 1
    answer = sign * int(str(abs(value))[::-1])
    return answer if LOWER <= answer <= UPPER else 0


def reverse_arithmetic(value):
    sign = -1 if value < 0 else 1
    remaining = abs(value)
    answer = 0
    while remaining:
        remaining, digit = divmod(remaining, 10)
        answer = answer * 10 + digit
        signed = sign * answer
        if signed < LOWER or signed > UPPER:
            return 0
    return sign * answer


class ReverseTests(unittest.TestCase):
    def check(self, value, expected):
        self.assertEqual(reverse_string(value), expected)
        self.assertEqual(reverse_arithmetic(value), expected)

    def test_sign_zero_and_trailing_zero(self):
        self.check(123, 321)
        self.check(-120, -21)
        self.check(0, 0)

    def test_overflow(self):
        self.check(1534236469, 0)
        self.check(-2147483648, 0)


if __name__ == "__main__":
    unittest.main()

Decision table

สถานการณ์StringArithmeticStack
input ใหญ่ในกรอบโจทย์O(d)O(d)O(d)
memory จำกัดใช้เพิ่มตามหลักดีที่สุดใช้เพิ่มตามหลัก
readabilityดีที่สุดต้องระวัง sign/overflowปานกลาง
streaming digitsต้องรวมข้อความประกอบได้ทีละหลักตามทิศที่รับเหมาะเมื่อรับย้อนลำดับ
ห้ามแก้ inputผ่านผ่านผ่าน
ภาษาที่ไม่มี big integerต้อง parse อย่างระวังguard ก่อนคูณguard ตอนประกอบ

Best default: arithmetic pop-push สำหรับโจทย์สัมภาษณ์ เพราะใช้พื้นที่คงที่และทำให้เห็น overflow contract; งานทั่วไปที่อนุญาต string เลือกวิธีที่ทีมอ่านง่ายกว่า

Edge cases

  • ศูนย์และตัวเลขที่ลงท้ายด้วยศูนย์หลายตัว
  • ค่าติดลบ โดยเฉพาะค่าต่ำสุดที่ค่าสัมบูรณ์อาจล้นในบางภาษา
  • ผลกลับเท่ากับขอบพอดี เทียบด้วย <=
  • Python ไม่ล้นเอง จึงต้องใส่ boundary ตามโจทย์

Recap

  • แยกเครื่องหมายจากหลักก่อน
  • ศูนย์นำหน้าหลังกลับหายตาม integer semantics
  • ตรวจช่วง signed 32-bit ทุกคำตอบ
  • เลือก arithmetic เมื่อ memory คงที่เป็นเงื่อนไขหลัก