002 — Sum of Digits¶
001-এ আমরা
%দিয়ে last bit ছুঁয়েছিলাম। আজ একই কৌশল সামান্য বদলে —% 10দিয়ে last digit ছোঁব, আর তার সাথে যোগ হবে আমাদের প্রথম "asol" loop। এই loop-টা পুরো level 0-এর হৃৎপিণ্ড; একবার হাতে এলে অর্ধেক problem এমনিই খুলে যাবে। ধীরে যাও, dry run-টা নিজে হাতে করো।
Source¶
- Original source: Classic beginner exercise
- Platform: Classic exercise
- Topic: Math-based programming fundamentals → Level 0: Absolute Basics
- Difficulty: Easy
- Pattern: digit extraction (sum)
- Basic idea inherited from: 001 (Even or Odd)
1. Problem in simple words¶
একটা integer n দেওয়া আছে। তার সব digit যোগ করে sum বের করতে হবে।
যেমন 1234 হলে digit গুলো 1, 2, 3, 4 — যোগফল 1 + 2 + 3 + 4 = 10।
আমরা str ছাড়া, শুধু arithmetic (% আর //) দিয়ে এটা করব — কারণ এই পদ্ধতিটাই পরের অনেক problem-এ ঘুরেফিরে লাগবে।
2. What is the math idea?¶
দুটো operator-এর জুটি — এদেরই বলি "digit-কাটার কাঁচি":
n % 10→ সংখ্যার last digit দেয়। যেমন1234 % 10 = 4।n // 10→ last digit ফেলে দেওয়া সংখ্যা দেয় (খোসা ছাড়ানো)। যেমন1234 // 10 = 123।
তাহলে কৌশল: বারবার last digit তুলে যোগফলে জমা করো, তারপর সেই digit ফেলে দাও — যতক্ষণ না সংখ্যাটা 0 হয়ে যায়।
এই while n > 0 কাঠামোটাকে বলে digit extraction loop — মুখস্থ না, বুঝে নাও।
3. Which basic idea does this inherit from?¶
সরাসরি 001 (Even or Odd) থেকে।
001-এ শিখেছিলাম — পুরো সংখ্যা না দেখে শুধু শেষটা দেখলেই চলে, আর সেই শেষটা ধরিয়ে দেয় % operator (n % 2 last bit)। আজ ঠিক সেই idea, শুধু 2-এর জায়গায় 10:
001-এ আমরা শুধু একবার শেষটা দেখেছিলাম। 002-এ এসে শেষটা দেখি, ফেলে দিই, আবার শেষটা দেখি — মানে একই idea-কে loop-এ বসিয়ে দিলাম। এটাই inheritance: পুরোনো চিন্তা + একটা নতুন মোচড়।
4. Real-life analogy¶
ভাবো একটা পয়সার কৌটো (piggy bank), মুখটা সরু — একসাথে অনেক কয়েন বের হয় না, এক-একটা করে ঝাঁকিয়ে ফেলতে হয়।
- প্রতিবার ঝাঁকুনিতে নিচ থেকে একটা কয়েন পড়ে →
n % 10(last digit তুলে নেওয়া) - সেই কয়েনের মূল্য তোমার মোট গোনায় যোগ করো →
total += digit - কৌটোয় বাকি কয়েন রয়ে গেল →
n //= 10(একটা কমে গেল)
কৌটো খালি (n = 0) হলে থামো। হাতে যা মোট জমেছে — সেটাই sum of digits। এক-একটা কয়েন এক-একটা digit, আর ঝাঁকুনিই হলো আমাদের loop।
5. Visual explanation¶
1234 থেকে এক-একটা digit বেরিয়ে আসছে, পাশে running total বাড়ছে — frame by frame:
শুরুতে: n = 1234, total = 0
frame 1: n = 1 2 3 [4] --%10--> 4 total = 0 + 4 = 4
^^^ --//10-> n = 123
frame 2: n = 1 2 [3] --%10--> 3 total = 4 + 3 = 7
^^^ --//10-> n = 12
frame 3: n = 1 [2] --%10--> 2 total = 7 + 2 = 9
^^^ --//10-> n = 1
frame 4: n = [1] --%10--> 1 total = 9 + 1 = 10
^^^ --//10-> n = 0 (কৌটো খালি, থামো!)
ফলাফল: total = 10
খেয়াল করো — digit গুলো বেরোচ্ছে ডান থেকে বামে (4, 3, 2, 1), কিন্তু যোগফলে ক্রম কোনো ব্যাপার না, তাই sum ঠিকঠাক 10।
6. Example input and output¶
input -> output (কীভাবে)
------------------------------
1234 -> 10 (1+2+3+4)
0 -> 0 (digit একটাই: 0, যোগফল 0)
7 -> 7 (একটাই digit)
99 -> 18 (9+9)
305 -> 8 (3+0+5, মাঝের 0-ও ঠিক ধরা পড়ে)
-1234 -> 10 (চিহ্ন বাদ দিয়ে digit গুলোই গোনা)
7. Brute force thinking¶
প্রথমে যেটা মাথায় আসে — সংখ্যাটাকে string বানিয়ে ফেলি, তারপর প্রতিটা অক্ষর আবার int করে যোগ করি:
def sum_of_digits_str(n):
total = 0
for ch in str(abs(n)): # "1234" -> '1','2','3','4'
total += int(ch) # প্রতিটা অক্ষরকে সংখ্যা বানিয়ে যোগ
return total
এটা কাজ করে, ঠিক উত্তর দেয়, পড়তেও সহজ। অনেক সময় এটাই যথেষ্ট। তাহলে সমস্যা কোথায়?
8. Why brute force may be slow¶
Time-এর দিক থেকে string version মোটেও "ধীর" নয় — দুটোই digit সংখ্যার সমান কাজ করে। কিন্তু কিছু লুকোনো খরচ আছে:
- বাড়তি জায়গা:
str(n)একটা নতুন string বানায় — মানে O(digit) extra space। arithmetic loop-এ সেটা লাগে না (O(1) space)। - type conversion: প্রতিটা অক্ষরে
int(ch)ডাকা — ছোট কিন্তু অপ্রয়োজনীয় overhead। - ভাষা-নির্ভরতা: Python-এ
str()সহজ, কিন্তু C++/Java-তে string-এ যাওয়া-আসা ঝামেলার। arithmetic পদ্ধতি যেকোনো ভাষায় একইভাবে চলে — interview-তে এটা বড় সুবিধা।
মূল কথা: string version দিয়ে উত্তর পাওয়া যায়, কিন্তু এই level-এর আসল লক্ষ্য হলো arithmetic loop-টা আয়ত্ত করা — কারণ পরের problem গুলোতে (reverse, palindrome, armstrong) string দিয়ে চালানো যায় না, ওখানে এই % 10 // 10 loop-ই লাগবে।
9. Better thinking¶
String বাদ — সরাসরি সংখ্যার উপরেই digit-কাটার কাঁচি চালাই:
def sum_of_digits(n):
n = abs(n) # negative হলেও digit একই
total = 0
while n > 0:
total += n % 10 # last digit যোগ করো
n //= 10 # last digit ফেলো
return total
কোনো নতুন string নেই, কোনো type conversion নেই — শুধু সংখ্যা আর দুটো operator। জায়গা লাগছে O(1), আর এই loop-টাই হবে তোমার সারা জীবনের সঙ্গী।
10. Thinking tweak¶
মাথায় এই ছবিটা গেঁথে নাও — একটা সংখ্যা মানে digit-এর একটা সারি, আর % 10 / // 10 দিয়ে তুমি সেই সারির ডান প্রান্ত থেকে একটা একটা করে খুলছ।
% 10= "ডান প্রান্তের জিনিসটা দেখাও" (পড়ে নাও, সরাও না)// 10= "ডান প্রান্তেরটা সরিয়ে দাও" (এক ঘর ছোট হলো)
এই দুটো একসাথে = "ডান থেকে বাঁয়ে digit ধরে হাঁটা"। আজ আমরা হাঁটতে হাঁটতে যোগ করছি; কাল 003-এ একই হাঁটায় শুধু গুনব (count); পরে armstrong-এ digit-কে power-এ তুলব। হাঁটাটা এক, শুধু "প্রতি ধাপে কী করব" বদলায়।
11. Step-by-step dry run¶
n = 1234 ধীরে চালাই। প্রতি ধাপে চারটে জিনিস লক্ষ করো — শুরুর n, তোলা digit, নতুন total, আর খোসা-ছাড়ানো n:
| step | n (শুরুতে) | d = n % 10 | total (পরে) | n //= 10 (পরে) |
|---|---|---|---|---|
| 1 | 1234 | 4 | 0 + 4 = 4 | 123 |
| 2 | 123 | 3 | 4 + 3 = 7 | 12 |
| 3 | 12 | 2 | 7 + 2 = 9 | 1 |
| 4 | 1 | 1 | 9 + 1 = 10 | 0 |
ধাপ 4-এর শেষে n = 0, তাই while n > 0 আর সত্যি নয় — loop থামল। total = 10 — ঠিক 1+2+3+4। নিজে খাতায় এই টেবিলটা আরেকবার বানাও 305 বা 99 দিয়ে, হাত যেন চিনে যায়।
12. Python solution¶
def sum_of_digits(n):
"""n-এর সব digit-এর যোগফল (arithmetic পদ্ধতি)।"""
n = abs(n) # negative-এর জন্য চিহ্ন বাদ
total = 0
while n > 0:
d = n % 10 # last digit
total += d # যোগফলে জমা
n //= 10 # last digit ফেলে দাও
return total
def sum_of_digits_str(n):
"""একই উত্তর, string পদ্ধতি (তুলনার জন্য)।"""
return sum(int(ch) for ch in str(abs(n)))
# --- ছোট test গুলো (সব pass করা উচিত) ---
assert sum_of_digits(1234) == 10
assert sum_of_digits(0) == 0 # 0-এর digit sum 0
assert sum_of_digits(7) == 7
assert sum_of_digits(99) == 18
assert sum_of_digits(305) == 8 # মাঝের 0-ও ধরা পড়ে
assert sum_of_digits(-1234) == 10 # চিহ্ন বাদ
assert sum_of_digits_str(1234) == 10 # দুই পদ্ধতি মেলে
print(sum_of_digits(1234)) # 10
print(sum_of_digits(305)) # 8
print(sum_of_digits(99)) # 18
print("সব test pass!")
13. Line-by-line explanation¶
negative হলে abs() দিয়ে চিহ্ন সরিয়ে দিই, যাতে while n > 0 ঠিকমতো চলে আর digit গুলোই গোনা হয় (চিহ্ন নয়)।
যোগফল রাখার পাত্র, শুরুতে খালি।
যতক্ষণ সংখ্যায় digit বাকি আছে (n এখনো 0 হয়নি) — ততক্ষণ চালাও। কৌটোয় কয়েন আছে কিনা, এই চেক।
last digit তুলে (% 10) যোগফলে জমা করি। (d-তে আলাদা করে রাখা বাধ্যতামূলক নয়, কিন্তু পড়তে সুবিধা।)
সবচেয়ে জরুরি লাইন — last digit ফেলে দিয়ে n-কে এক ঘর ছোট করি। এটা না থাকলে n কখনো 0 হবে না → loop চিরকাল চলবে (infinite loop)।
sum_of_digits_str হলো generator expression — str(abs(n))-এর প্রতিটা অক্ষর int() করে sum() যোগ করে। ছোট আর সুন্দর, কিন্তু ভেতরে string বানায়।
14. Output walkthrough¶
চালালে ছাপবে:
তিনটা সংখ্যা তিনটা print থেকে — 1234 → 10, 305 → 8, 99 → 18। তার আগে সব assert চুপচাপ pass করেছে (একটাও fail করলে সেখানেই থেমে error দিত)। শেষ লাইন সব test pass! মানে দুই পদ্ধতির উত্তর মিলেছে, সব ঠিক।
15. Time complexity¶
O(number of digits) = O(log₁₀ n)। loop প্রতিবার n-কে 10 দিয়ে ভাগ করে, তাই যতগুলো digit ততবারই ঘোরে। 9-digit সংখ্যা হলে মাত্র 9 বার — সংখ্যা যত বড় হোক, digit সংখ্যা তার লগারিদমের সমান, তাই খুবই দ্রুত।
(কেন log? কারণ একটা সংখ্যার digit সংখ্যা ≈ log₁₀(n) + 1। 1000-এর 4 digit, 10000-এর 5 — দশগুণ বাড়লে digit বাড়ে মোটে একটা।)
16. Space complexity¶
O(1) — arithmetic version-এ শুধু total, d, n — গুটিকয় variable, সংখ্যার আকারের সাথে বাড়ে না। (string version-এ O(digit) — কারণ পুরো string-টা মেমরিতে বানায়।)
17. Common mistakes¶
n //= 10ভুলে যাওয়া — সবচেয়ে কমন ভুল। ছাড়া পড়লেnএকই থেকে যায়,while n > 0কখনো শেষ হয় না → infinite loop।%আর//উল্টে ফেলা —n % 10digit দেয়,n // 10খোসা ফেলে। উল্টে দিলে সব ভুল। মনে রাখো:%= "যা বাকি",//= "কতবার ঢুকল"।% 2লিখে ফেলা — 001-এর অভ্যাসে অনেকে% 2লেখে; digit চাই বলে% 10লাগবে।- negative ভুলে যাওয়া —
abs(n)না নিলে-1234-এwhile n > 0একবারও চলবে না, ভুল করে 0 ফেরত আসবে। totalবাইরে initialize না করা —total = 0loop-এর ভেতরে বসালে প্রতিবার রিসেট হয়ে যাবে।
18. Harder problems that inherit this idea¶
এই digit extraction loop-ই নিচের সবগুলোর ভিত্তি:
- 007 — Digital Root (এই repo) — digit sum বারবার নাও যতক্ষণ না এক digit থাকে (9875 → 29 → 11 → 2)। এটাই digit sum-এর সরাসরি বড় ভাই; এর সাথে আছে
% 9-এর জাদু। সম্পর্কিত: LeetCode — Add Digits (https://leetcode.com/problems/add-digits/)। - 006 — Armstrong Number (এই repo) — একই loop, কিন্তু digit যোগ না করে
digit ** kযোগ করো। - LeetCode — Happy Number (https://leetcode.com/problems/happy-number/) — এখানে digit-এর বর্গের যোগফল বারবার নিতে হয়; ভেতরের ইঞ্জিন সেই digit extraction loop।
19. Pattern learned¶
Digit extraction loop — while n > 0: d = n % 10; (d-কে কাজে লাগাও); n //= 10। এটাই level 0-এর সবচেয়ে দরকারি, সবচেয়ে বেশিবার-ফেরা pattern। আজ "কাজে লাগাও" = যোগ করা; কাল শুধু এই এক লাইন বদলে count, power-sum, reverse — সব হবে। loop-টা একবার চোখ বন্ধ করে লিখতে পারলে অর্ধেক যুদ্ধ জেতা।
20. Final summary¶
ভবিষ্যতের আমাকে এক লাইনে: "digit sum = while loop-এ n % 10 তুলে যোগ করো, n //= 10 দিয়ে ফেলে দাও, n = 0 হলে থামো। 001-এর last-digit idea-ই এখানে loop হয়ে ফিরেছে — আর এই loop-টাই পরের সব digit problem-এর মা।"
আগের ধাপ → 001 — Even or Odd। পরের ধাপ → 003 — Count Digits (একই loop, এবার গুনব)। আরও দূরে → 007 — Digital Root।
ফিরে দেখা: এই level-এর map → ../README.md · এই note-টা যে ছকে লেখা → ../../../templates/math-problem-note-template.md।
21. JavaScript solution (with test cases)¶
Python-এ integer division // আছে, JS-এ নেই — তাই খোসা-ছাড়ানোতে Math.floor(n / 10) লাগবে (নিচের টীকা)।
function sumOfDigits(n) {
n = Math.abs(n); // negative হলেও digit একই
let total = 0;
while (n > 0) {
total += n % 10; // last digit তুলে যোগ
n = Math.floor(n / 10); // JS-এ // নেই → Math.floor দিয়ে integer division
}
return total;
}
// ছোট throwing assert — fail করলে এখানেই থেমে error দেবে
const assert = (cond, msg = "") => { if (!cond) throw new Error("FAIL " + msg); };
// ---- test cases ----
assert(sumOfDigits(1234) === 10, "1234");
assert(sumOfDigits(0) === 0, "0");
assert(sumOfDigits(99) === 18, "99");
assert(sumOfDigits(305) === 8, "305"); // মাঝের 0-ও ধরা পড়ে
assert(sumOfDigits(-1234) === 10, "-1234"); // চিহ্ন বাদ
console.log("সব JS test pass!");
JS টীকা: JavaScript-এ floor-division operator নেই;
n = Math.floor(n / 10)(অথবা ছোট সংখ্যায়n = (n / 10) | 0) ব্যবহার করো — সরাসরিn / 10দিলে decimal থেকে যাবে আর loop ভুল চলবে। আরMath.absআগে নাও, কারণ JS-এ-1234 % 10 === -4।
22. TypeScript solution (with test cases)¶
function sumOfDigits(n: number): number {
n = Math.abs(n);
let total = 0;
while (n > 0) {
total += n % 10;
n = Math.trunc(n / 10); // Math.trunc = "ভগ্নাংশ ফেলে দাও" — intent পরিষ্কার
}
return total;
}
// ---- typed test table: [input, expected] ----
const cases: ReadonlyArray<readonly [number, number]> = [
[1234, 10], [0, 0], [99, 18], [305, 8], [-1234, 10],
];
for (const [input, want] of cases) {
const got = sumOfDigits(input);
if (got !== want) throw new Error(`FAIL ${input}: got ${got}, want ${want}`);
}
console.log("সব TS test pass!");
TS টীকা: test গুলো একটা
ReadonlyArray<readonly [number, number]>table-এ রাখলে নতুন case যোগ করা সহজ আর tuple type ভুল-আকারের case compile-time-এই আটকায়। এটাই data-driven / table-driven testing — production test suite-এ খুব কমন।
23. কোথায় কাজে লাগে (real-world use)¶
Digit extraction (% 10 / / 10) loop-টা অসংখ্য জায়গায় লুকিয়ে থাকে:
- Checksum / validation: Luhn algorithm (credit/debit card নম্বর যাচাই) মূলত digit-sum-ভিত্তিক; ISBN, IMEI-তেও digit-sum check।
- Cast-out-nines: হিসাব দ্রুত যাচাই করতে digit sum mod 9 (পরের problem digital-root-এর ভিত্তি)।
- Hashing / bucketing: সরল hash-এ digit sum দিয়ে bucket বাছা।
- Number formatting: currency/locale formatting-এ digit ধরে ধরে process।
- Base conversion: ঠিক এই
% base// baseloop দিয়েই এক base থেকে আরেক base-এ সংখ্যা রূপান্তর।
মূল pattern digit extraction loop — একবার হাতে এলে reverse, palindrome, base-conversion, happy-number সব এর উপরেই দাঁড়ায়।
মনে রাখার নিয়ম (legal): সব নিজের ভাষায় লেখা; problem statement copy করা হয়নি; official link শুধু attribution-এর জন্য; "asked by Google/Amazon" এমন দাবি করা হয়নি — বরং "common interview pattern" লেখা।