# 004 — Reverse Number

> 002-003 জুড়ে আমরা digit *ভাঙা* শিখেছি — `% 10` দিয়ে তুলে, `// 10` দিয়ে ফেলে। আজ প্রথমবার উল্টোটা শিখব: digit জুড়ে নতুন একটা সংখ্যা *বানানো*। মূল মন্ত্র একটাই লাইন — `rev = rev * 10 + d`। এই এক লাইন একবার বুঝে গেলে 005 (palindrome) প্রায় বিনা পরিশ্রমে হাতে চলে আসবে। ধীরে যাও, dry run-টা নিজে হাতে করো।

<div class="problem-source" markdown="1">

<p class="source-label" id="source">Problem link ও উৎস</p>

- Original source: Classic beginner exercise (related practice: LeetCode — Reverse Integer — <https://leetcode.com/problems/reverse-integer/>)
- Platform: Classic exercise / LeetCode (related)
- Topic: Math-based programming fundamentals → Level 0: Absolute Basics
- Difficulty: Easy
- Pattern: number building (`rev * 10 + d`)
- Basic idea inherited from: 002 (Sum of Digits)

</div>

## প্রশ্ন ও উদাহরণ {#problem}

### সহজ করে প্রশ্ন {#1-problem-in-simple-words}

একটা integer `n` দেওয়া আছে। তার digit গুলোকে **উল্টো করে** নতুন একটা সংখ্যা বানাতে হবে।

যেমন `1234` উল্টালে হয় `4321`। `120` উল্টালে হয় `21` (সামনের 0 আপনাআপনি মিলিয়ে যায় — `021` মানে তো `21`)।

আমরা str ছাড়া, শুধু arithmetic (`%`, `//`, আর একটা গুণ-যোগ) দিয়ে এটা করব — কারণ এই "সংখ্যা বানানো" কৌশলটা পরের অনেক problem-এ ঘুরেফিরে লাগবে।

### Input ও output {#6-example-input-and-output}

```text
input   ->  output   (কীভাবে)
------------------------------
 1234   ->   4321
    7   ->      7    (একটাই digit, উল্টালেও একই)
    0   ->      0    (digit একটাই: 0)
  120   ->     21    <-- সাবধান! সামনের 0 মিলিয়ে যায় (021 = 21)
 1000   ->      1    (0001 = 1)
-1234   ->  -4321    (চিহ্ন রেখে digit উল্টানো)
```

ওই `120 -> 21` লাইনটা মনে রাখো — reverse করলে trailing zero গুলো leading zero হয়ে যায়, আর সংখ্যায় leading zero থাকে না, তাই তারা মিলিয়ে যায়। এটা bug নয়, গণিতের স্বাভাবিক আচরণ।

### চেনা উদাহরণে বোঝা {#4-real-life-analogy}

ভাবো তুমি একটা খালি **শেলফে বই সাজাচ্ছ**, কিন্তু নিয়ম হলো — প্রতিটা নতুন বই সবসময় বাঁ-প্রান্তে রাখতে হবে।

- নতুন বই এলে, শেলফে আগে থেকে থাকা সব বই **এক ঘর ডানে সরিয়ে** বাঁয়ে জায়গা করো → এটাই `rev * 10` (সবাইকে সরানো)
- তারপর নতুন বইটা বাঁ-প্রান্তে বসাও → এটাই `+ d`

কৌটো (n) থেকে বই বেরোচ্ছে ডান প্রান্ত থেকে (4, তারপর 3, তারপর 2, 1), কিন্তু শেলফে (rev) সবসময় বাঁয়ে বসছে। তাই যে বই আগে বেরিয়েছে (4) সে শেলফের সবচেয়ে বাঁয়ে — মানে সংখ্যাটা উল্টে গেল! `4321`।

## ভিত্তির ধারণা {#idea}

### আগের কোন ধারণাটি লাগবে {#3-which-basic-idea-does-this-inherit-from}

সরাসরি **002 (Sum of Digits)** থেকে — peeling loop (`while n > 0: ... n //= 10`) হুবহু এক।

002 আর 004-এর ভেতরের লাইন পাশাপাশি রাখো:

```
002 (sum):      total = total + (n % 10)       # শুধু মান জমাও
004 (reverse):  rev   = rev * 10 + (n % 10)    # মান জমাও, কিন্তু আগে এক ঘর বামে ঠেলে
                        ^^^^^^^^
                   নতুন অংশ — জায়গা বানানো
```

দেখো — 002-এ আমরা শুধু digit-এর মান যোগ করেছিলাম (ক্রম গুরুত্বহীন ছিল)। 004-এ ক্রম **খুব** গুরুত্বপূর্ণ, তাই প্রতিটা পুরোনো digit-কে বামে ঠেলে জায়গা করে দিই। peeling এক, কিন্তু "প্রতি ধাপে কী করব" বদলে গেল — এটাই inheritance: পুরোনো loop + একটা নতুন মোচড়।

### ভেতরের অঙ্ক {#2-what-is-the-math-idea}

002-এর digit-কাটার কাঁচি (`% 10` আর `// 10`) এখানেও আছে — কিন্তু সাথে একটা নতুন জিনিস: **জায়গা বানানো**।

মূল চিন্তা: ডান দিক থেকে digit তুলছি, আর প্রতিটা নতুন digit-কে বসানোর আগে আগের সব digit-কে **এক ঘর বামে ঠেলে দিচ্ছি** (`× 10`), তারপর নতুন digit-টা একদম ডানে বসাচ্ছি (`+ d`):

```
rev = 0
যতক্ষণ n > 0:
    d = n % 10           # last digit তুলে নাও
    rev = rev * 10 + d   # আগের সব এক ঘর বামে ঠেলো, d-কে ডানে বসাও
    n //= 10             # সেই digit ফেলে দাও
```

`rev * 10` হলো place value-র জাদু — একটা সংখ্যাকে 10 দিয়ে গুণ মানে প্রতিটা digit এক ঘর বামে সরে গিয়ে ডানে একটা খালি (0) ঘর তৈরি হয়। সেই খালি ঘরেই নতুন digit বসে।

## ধাপে ধাপে সমাধান {#walkthrough}

### প্রথম সরল উপায় {#7-brute-force-thinking}

প্রথমে যেটা মাথায় আসে — সংখ্যাটাকে **string বানিয়ে** Python-এর slicing দিয়ে উল্টে দিই, তারপর আবার int করি:

```python
def reverse_number_str(n):
    sign = -1 if n < 0 else 1
    rev_str = str(abs(n))[::-1]   # "1234" -> "4321"
    return sign * int(rev_str)
```

`[::-1]` হলো Python-এর "পুরো জিনিসটা উল্টে দাও" slicing। এটা কাজ করে, ঠিক উত্তর দেয়, পড়তেও সহজ। `int()` করার সময় leading zero এমনিই মিলিয়ে যায় (`int("021") == 21`)। তাহলে সমস্যা কোথায়?

### কোথায় বেশি কাজ হতে পারে {#8-why-brute-force-may-be-slow}

Time-এর দিক থেকে string version "ধীর" নয় — দুটোই digit সংখ্যার সমান কাজ করে। কিন্তু কিছু লুকোনো খরচ আর সীমাবদ্ধতা আছে:

- **বাড়তি জায়গা:** `str(n)` আর উল্টানো string — দুটো নতুন string বানায়, মানে O(digit) extra space। arithmetic loop-এ সেটা লাগে না (O(1) space)।
- **ভাষা-নির্ভরতা:** Python-এ `[::-1]` সহজ, কিন্তু C++/Java-তে string উল্টে আবার সংখ্যায় ফেরানো ঝামেলার। arithmetic পদ্ধতি **যেকোনো ভাষায়** একইভাবে চলে — interview-তে এটা বড় সুবিধা।
- **overflow check করা যায় না:** LeetCode Reverse Integer-এর মতো problem উল্টানো সংখ্যা 32-bit সীমা ছাড়ালে 0 চায়। string পদ্ধতিতে আগে থেকে সেটা ধরা কঠিন; arithmetic পদ্ধতিতে প্রতি ধাপে check বসানো সহজ।

মূল কথা: string version দিয়ে উত্তর পাওয়া যায়, কিন্তু এই level-এর **আসল লক্ষ্য** হলো `rev * 10 + d` কৌশলটা আয়ত্ত করা — কারণ 005 (palindrome)-এ string ছাড়াই reverse লাগবে।

### আরও ভালোভাবে ভাবা {#9-better-thinking}

String বাদ — সরাসরি সংখ্যার উপরেই "ভাঙো আর বানাও" loop চালাই:

```python
def reverse_number(n):
    sign = -1 if n < 0 else 1
    n = abs(n)
    rev = 0
    while n > 0:
        d = n % 10
        rev = rev * 10 + d   # বামে ঠেলো, নতুন digit বসাও
        n //= 10
    return sign * rev
```

কোনো নতুন string নেই — শুধু সংখ্যা আর তিনটে operation। জায়গা লাগছে O(1)। ডান থেকে digit তুলে বাঁয়ে জোড়ার ফলেই সংখ্যাটা উল্টে যায়।

### ভাবনার পরিবর্তন {#10-thinking-tweak}

আসল "আহা!" মুহূর্ত এক বাক্যে: **সংখ্যাকে 10 দিয়ে গুণ মানে সব digit এক ঘর বামে ঠেলে ডানে একটা খালি ঘর বানানো — সেই খালি ঘরেই নতুন digit বসে।**

- ভাঙার সময় (002): `% 10` দিয়ে ডান প্রান্ত *পড়ি*, `// 10` দিয়ে ডান প্রান্ত *সরাই* → সংখ্যা ছোট হয়।
- বানানোর সময় (004): `× 10` দিয়ে বাঁয়ে *ঠেলি*, `+ d` দিয়ে ডানে *বসাই* → সংখ্যা বড় হয়।

দুটো একে অন্যের আয়না। আর যেহেতু আমরা ডান থেকে digit তুলে বাঁয়ে বসাচ্ছি, ক্রম উল্টে যায় — এটাই reverse। এই `rev * 10 + d` লাইন পরে অনেক জায়গায় ফিরবে (palindrome, এমনকি বড় হয়ে "string to integer" parsing-এও)।

### ছবিতে বোঝা {#5-visual-explanation}

`1234` থেকে এক-একটা digit বেরিয়ে rev-এ জুড়ছে — frame by frame দেখো কীভাবে rev "বামে ঠেলে, ডানে বসাও" নিয়মে বড় হয়:

```text
শুরুতে: n = 1234, rev = 0

frame 1:  d = 4   rev = 0×10 + 4   = 4        n -> 123
frame 2:  d = 3   rev = 4×10 + 3   = 43       n -> 12
frame 3:  d = 2   rev = 43×10 + 2  = 432      n -> 1
frame 4:  d = 1   rev = 432×10 + 1 = 4321     n -> 0   (থামো!)

ফলাফল: rev = 4321
```

`rev * 10` কী করছে সেটা আলাদা করে দেখো — পুরোনো digit গুলো বামে সরে, ডানে একটা 0 ঘর তৈরি হয়, সেখানেই নতুন d বসে:

```text
rev = 43   ->   43 × 10 = 430   ->   430 + 2 = 432
              [4][3][_]              [4][3][2]
               ^বামে ঠেলা^           ^d ডানে বসল^
```

### ছোট input-এ ধাপে ধাপে {#11-step-by-step-dry-run}

`n = 1234`। প্রতি ধাপে চারটে জিনিস লক্ষ করো — শুরুর n, তোলা digit, নতুন rev, আর খোসা-ছাড়ানো n:

| step | n (শুরুতে) | d = n % 10 | rev = rev*10 + d | n //= 10 (পরে) |
| --- | --- | --- | --- | --- |
| 1 | 1234 | 4 | 0×10 + 4 = 4 | 123 |
| 2 | 123 | 3 | 4×10 + 3 = 43 | 12 |
| 3 | 12 | 2 | 43×10 + 2 = 432 | 1 |
| 4 | 1 | 1 | 432×10 + 1 = 4321 | 0 |

ধাপ 4-এর শেষে `n = 0`, তাই `while n > 0` আর সত্যি নয় — loop থামল। **rev = 4321** — ঠিক উল্টো সংখ্যা। নিজে খাতায় এই টেবিলটা আরেকবার বানাও `120` দিয়ে, দেখবে rev = 21 (সামনের 0 মিলিয়ে গেছে)।

## কোড ও ব্যাখ্যা {#code}

### Python {#12-python-solution}

```python
def reverse_number(n):
    """n-এর digit উল্টে নতুন সংখ্যা (arithmetic পদ্ধতি, চিহ্ন রেখে)।"""
    sign = -1 if n < 0 else 1
    n = abs(n)
    rev = 0
    while n > 0:
        d = n % 10           # last digit
        rev = rev * 10 + d   # বামে ঠেলে ডানে বসাও
        n //= 10             # সেই digit ফেলো
    return sign * rev


def reverse_number_str(n):
    """একই উত্তর, string পদ্ধতি (তুলনার জন্য)।"""
    sign = -1 if n < 0 else 1
    return sign * int(str(abs(n))[::-1])


# --- ছোট test গুলো (সব pass করা উচিত) ---
assert reverse_number(1234) == 4321
assert reverse_number(7) == 7
assert reverse_number(0) == 0          # 0 উল্টালে 0
assert reverse_number(120) == 21       # trailing 0 মিলিয়ে যায়
assert reverse_number(1000) == 1
assert reverse_number(-1234) == -4321  # চিহ্ন রেখে উল্টানো
assert reverse_number_str(1234) == 4321    # দুই পদ্ধতি মেলে
assert reverse_number_str(-120) == -21

print(reverse_number(1234))   # 4321
print(reverse_number(120))    # 21
print(reverse_number(-1234))  # -4321
print("সব test pass!")
```

### কোডের প্রতিটি অংশ {#13-line-by-line-explanation}

```
    sign = -1 if n < 0 else 1
```

চিহ্নটা আগে আলাদা করে রেখে দিই। negative হলে `-1`, নাহলে `1`। শেষে এই sign দিয়ে গুণ করব, যাতে `-1234` উল্টে `-4321` হয় (digit গুলো উল্টায়, minus নয়)।

```
    n = abs(n)
```

এবার চিহ্ন সরিয়ে শুধু digit নিয়ে কাজ করি, যাতে `while n > 0` ঠিকমতো চলে।

```
    rev = 0
```

বানানো সংখ্যা রাখার পাত্র, শুরুতে খালি (0)।

```
    while n > 0:
        d = n % 10
        rev = rev * 10 + d
        n //= 10
```

চেনা peeling loop, কিন্তু মাঝের লাইনটাই নতুন। `n % 10` last digit তোলে; `rev * 10 + d` আগের rev-কে এক ঘর বামে ঠেলে নতুন digit ডানে বসায়; `n //= 10` সেই digit ফেলে দেয়। **`n //= 10` না থাকলে n কখনো 0 হবে না → infinite loop।**

```
    return sign * rev
```

শেষে আসল চিহ্নটা ফিরিয়ে দিই।

`reverse_number_str` হলো shortcut — `str(abs(n))[::-1]` সংখ্যাকে string বানিয়ে উল্টে দেয়, `int()` আবার সংখ্যায় ফেরায় (leading zero আপনাআপনি মেলে), তারপর sign বসায়।

### Output মিলিয়ে দেখা {#14-output-walkthrough}

চালালে ছাপবে:

```
4321
21
-4321
সব test pass!
```

তিনটা সংখ্যা তিনটা `print` থেকে: `reverse_number(1234)` → 4321, `reverse_number(120)` → 21 (trailing 0 মিলিয়ে গেছে!), `reverse_number(-1234)` → -4321 (চিহ্ন ঠিক আছে)। তার আগে সব `assert` চুপচাপ pass করেছে (একটাও fail করলে সেখানেই থেমে error দিত)। শেষ লাইন `সব test pass!` মানে দুই পদ্ধতির উত্তর মিলেছে, সব ঠিক।

## খরচ ও সাধারণ ভুল {#cost}

### সময় {#15-time-complexity}

**O(number of digits) = O(log₁₀ n)**। loop প্রতিবার `n`-কে 10 দিয়ে ভাগ করে, তাই যতগুলো digit ততবারই ঘোরে। 9-digit সংখ্যা হলে মাত্র 9 বার — সংখ্যা যত বড় হোক, digit সংখ্যা তার লগারিদমের সমান, তাই খুবই দ্রুত।

(কেন `log`? কারণ একটা সংখ্যার digit সংখ্যা ≈ `log₁₀(n) + 1`। দশগুণ বড় হলে digit বাড়ে মোটে একটা।)

### অতিরিক্ত জায়গা {#16-space-complexity}

**O(1)** — arithmetic version-এ শুধু `sign`, `rev`, `d`, `n` — গুটিকয় variable, সংখ্যার আকারের সাথে বাড়ে না। (string version-এ O(digit) — কারণ পুরো string দুবার মেমরিতে বানায়।)

### যে ভুলগুলো এড়াতে হবে {#17-common-mistakes}

1. **`rev = rev * 10 + d` ভুলে শুধু `rev += d` লেখা** — তাহলে digit গুলো জায়গা না পেয়ে যোগ হয়ে যাবে (1234 → 10, sum of digits!)। বামে ঠেলার `* 10`-টাই reverse-এর প্রাণ।
2. **`n //= 10` ভুলে যাওয়া** — n একই থেকে যায়, `while n > 0` কখনো শেষ হয় না → **infinite loop**।
3. **negative-এ চিহ্ন হারানো বা ভুল করা** — আগে `sign` আলাদা রেখে `abs(n)` নিলে নিরাপদ; নাহলে Python-এ `-1234 % 10` হয় 6 (অপ্রত্যাশিত), সব গুলিয়ে যায়।
4. **trailing zero নিয়ে দুশ্চিন্তা** — `120 -> 21` ঠিকই; leading zero গণিতে মিলিয়ে যায়, এটা কোনো bug নয়।
5. **LeetCode-এ 32-bit overflow ভুলে যাওয়া** — Python-এ int unbounded, কিন্তু Reverse Integer problem ইচ্ছে করে 32-bit সীমা চাপায় — তখন প্রতি ধাপে বা শেষে নিজে check করে 0 ফেরাতে হয়।

## শেখা ও পরের অনুশীলন {#practice}

### এই ধারণার পরের অনুশীলন {#18-harder-problems-that-inherit-this-idea}

- **005 — Palindrome Number** (এই repo) — সংখ্যাটা reverse বানিয়ে original-এর সাথে মেলানোই পুরো সমাধান; এটা 004-এর সরাসরি পরের ধাপ।
- **LeetCode — Reverse Integer** (<https://leetcode.com/problems/reverse-integer/>) — হুবহু এই reverse, কিন্তু সাথে 32-bit overflow check; `rev * 10 + d` লাইনটাই কেন্দ্র।
- **LeetCode — String to Integer (atoi)** (<https://leetcode.com/problems/string-to-integer-atoi/>) — উল্টোমুখী আত্মীয়: digit গুলো বাঁ থেকে পড়ে `result = result * 10 + d` দিয়ে সংখ্যা বানানো — একই "বামে ঠেলে ডানে বসাও" মন্ত্র।

### কৌশলটি মনে রাখুন {#19-pattern-learned}

**Number building via `rev * 10 + d`** — digit থেকে সংখ্যা *বানানোর* মূল কৌশল, ঠিক digit extraction-এর আয়না। মনে রাখার বড় শিক্ষা: **`× 10` মানে জায়গা বানানো (বামে ঠেলা), `+ d` মানে নতুন digit বসানো।** ডান থেকে তুলে বাঁয়ে বসালে সংখ্যা উল্টে যায়; বাঁ থেকে পড়লে একই সংখ্যা ফিরে আসে — এই দুই ব্যবহারই পরে বারবার ফিরবে।

### নিজেকে যাচাই করুন {#20-final-summary}

ভবিষ্যতের আমাকে এক লাইনে: *"reverse = peeling loop-এ `% 10` তুলে `rev = rev * 10 + d` দিয়ে বানাও, `n //= 10` দিয়ে ফেলো। `× 10` = জায়গা বানানো, `+ d` = digit বসানো। চিহ্ন আগে আলাদা রেখো; trailing zero মিলিয়ে যাওয়া স্বাভাবিক।"*

আগের ধাপ → [002 — Sum of Digits](002-sum-of-digits.md) (যেখান থেকে peeling loop পেলাম)। শিকড়ে → [001 — Even or Odd](001-even-or-odd.md)। পরের ধাপ → [005 — Palindrome Number](005-palindrome-number.md) (এই reverse-কে কাজে লাগিয়ে)।

ফিরে দেখা: এই level-এর map → [../README.md](../README.md) · এই note-টা যে ছকে লেখা → [../../../templates/math-problem-note-template.md](../../../templates/math-problem-note-template.md)।

---

> **মনে রাখার নিয়ম (legal):** সব নিজের ভাষায় লেখা; problem statement copy করা হয়নি; official link শুধু attribution-এর জন্য; "asked by Google/Amazon" এমন দাবি করা হয়নি — বরং "common interview pattern" লেখা।
