01A loop divides n by 2 until it reaches 1. What is its Big O?
O(log n). Each pass halves the work, so 1,000,000 needs only about 20 passes.
02Before you code, which questions do you ask about the input?
Its range, an empty input, duplicates, negative values, and what to return when there is no answer.
03Why read the value range in the limits, not only n?
The values tell you when a number gets too big. JavaScript numbers stay exact only up to about 9 × 10¹⁵.
On paper, 121 is a row of three digits. To your code, it is one value. You cannot index into it like an array.
This lesson gives you one small loop that takes a number apart, digit by digit. Count digits, reverse a number, check a palindrome: all of them use that same loop.
The one move: peel the last digit
Two operations do all the work:
n % 10gives the last digit. The after dividing by 10 is always the units digit.n / 10, with the decimals thrown away, drops the last digit. Each language writes that differently:
| Language | Drop the last digit | Why |
|---|---|---|
| Java | n / 10 | int division drops the decimals: 7 / 2 is 3 |
| Python | n // 10 | / gives a float (3.5); // rounds down |
| TypeScript | Math.floor(n / 10) | / gives decimals, so round down |
Repeat both until nothing is left:
┌──────────────────────────────────────────────┐ │ │ │ n last digit what is left │ │ n % 10 floor(n / 10) │ │ 7789 9 778 │ │ 778 8 77 │ │ 77 7 7 │ │ 7 7 0 ← stop │ │ │ └──────────────────────────────────────────────┘
The digits come out in reverse order: 9, 8, 7, 7. Keep that in mind. It is the reason reversing a number is easy.
void printDigits(int n) {
while (n > 0) {
int digit = n % 10; // the last digit
System.out.println(digit);
n = n / 10; // drop it
}
}The loop runs only while n > 0, so handle the sign first. The languages disagree on negative numbers:
-7 % 10is-7in Java and TypeScript, but3in Python.-7 / 10is0in Java.-7 // 10is-1in Python, andMath.floor(-7 / 10)is-1in TypeScript.
Make the number positive, peel it, then put the sign back.
What it costs
Each pass removes one digit. So the loop runs once per digit.
| n | Digits | Passes |
|---|---|---|
| 9 | 1 | 1 |
| 5,000 | 4 | 4 |
| 2,147,483,647 | 10 | 10 |
A number n has about log₁₀ n digits, so the loop is O(log n). It is the halving loop from Time and space complexity, cutting by 10 each time instead of 2.
Read the problem
Read backwards, it is still 121.
Read backwards, it is 121-.
Read backwards, it is 01.
- −2³¹ ≤ x ≤ 2³¹ − 1
- follow-up: no strings
Which pattern? Decide first, then open.
“reads the same from left to right and from right to left”a palindrome: reverse it and compare
“integer, without converting it to a string”peel the digits with % 10 and / 10
pattern: Maths
Ask these before you code:
- Negative numbers? The minus sign sits only at the front. So every negative number is
false. - Ends in 0? 10 read backwards is "01". Only 0 itself is a palindrome that ends in 0.
- One digit? Always
true. - How big? At most 10 digits. Speed is not the problem here. The follow-up is: solve it without a string.
The input is one number, not an array. So the cost depends on its digit count, not on a length n.
Brute force: turn it into a string
The first idea: make a string, reverse it, compare.
┌──────────────────────────────────────────────────┐ │ │ │ 1221 ──to text──▶ "1221" ──reverse──▶ "1221" │ │ │ │ │ │ └───── equal? ──────┘ │ │ true │ │ │ └──────────────────────────────────────────────────┘
boolean isPalindrome(int x) {
String s = String.valueOf(x);
return s.equals(new StringBuilder(s).reverse().toString());
}- The text of -121 is
"-121", and its reverse is"121-". So negatives returnfalsewith no extra check. - Time: one pass to build the string, one to reverse it, one to compare. O(d) for d digits.
- Space: two strings of d characters, so O(d).
It is correct and fast. But the follow-up says no strings, and the interviewer wants to see you work with the number itself.
The key insight
You can build the reverse with arithmetic. The peel loop already hands you the digits from right to left. Each new digit goes on the end of rev:
┌───────────────────────────────────────────────────┐ │ │ │ rev = 12 rev × 10 = 120 + 2 = 122 │ │ ┌───┬───┐ ┌───┬───┬───┐ ┌───┬───┬───┐ │ │ │ 1 │ 2 │ ──▶ │ 1 │ 2 │ 0 │ ──▶ │ 1 │ 2 │ 2 │ │ │ └───┴───┘ └───┴───┴───┘ └───┴───┴───┘ │ │ │ └───────────────────────────────────────────────────┘
So one line does it: rev = rev * 10 + digit.
One trap: the loop eats x until it is 0. Save a copy first, so you have something to compare with at the end.
Optimal: reverse with maths
- Return
falsefor a negative number. - Save
original = x. Startrevat 0. - While
x > 0: peel the last digit, push it ontorev, drop it fromx. - Return whether
revequalsoriginal.
Here it is on 1221. The pointer marks the digit each pass reads.
1/6Start with rev = 0. Save a copy: original = 1221.
boolean isPalindrome(int x) {
if (x < 0) return false;
int original = x;
long rev = 0; // long: a reversed int can pass the int limit
while (x > 0) {
int digit = x % 10;
rev = rev * 10 + digit; // push the digit onto the end of rev
x = x / 10; // drop it from x
}
return rev == original;
}- Time: one pass per digit, so O(d), which is O(log x).
- Space: two numbers, so O(1).
- 0: the loop never runs,
revstays 0, and 0 equals 0. True. - 10:
revends as 1, which is not 10. False, with no special case. - Big values: 2,147,483,647 reversed is 7,463,847,412. That is past the largest Java
int, so the Java version keepsrevin along. A Pythoninthas no limit, and a TypeScript number holds it exactly.
Side by side
| Approach | Idea | Time | Extra space | Fits? |
|---|---|---|---|---|
| String | reverse the text | O(d) | O(d) | yes, but breaks the follow-up |
| Maths | rev = rev * 10 + digit | O(d) | O(1) | yes |
Here d is the digit count, at most 10.
How to spot this pattern
| Signal in the problem | Why it points here |
|---|---|
| "digits of a number" | peel them with % 10 |
| "reverse the number" | rev = rev * 10 + digit |
| "without converting to a string" | the interviewer wants the peel loop |
| a check on each digit | one loop, one running answer |
The template. Only the middle line changes from problem to problem:
while (n > 0) {
int digit = n % 10;
// use digit: count it, add it, compare it
n = n / 10;
}The other problems on this lesson's list:
| Problem | What changes in the loop | Watch out |
|---|---|---|
| Count all Digits | add 1 to count | 0 has one digit, but the loop never runs |
| Count odd digits | add 1 when digit % 2 == 1 | 0 has no odd digits |
| Reverse a number | rev = rev * 10 + digit | 120 reverses to 21. In Java, check for int overflow (LeetCode "Reverse Integer") |
| Largest digit | best = max(best, digit) | start best at 0 |
| Armstrong number | add digit to the power k | count the k digits first, then compare with a copy |
An uses the loop twice: once to count the k digits, once to add each digit to the power k. 153 is 1 + 125 + 27, so it is one.
Factorial is the odd one out. It is a plain loop that multiplies 1 × 2 × … × n, so O(n).
Watch the size. Factorials grow fast:
- Java: 12! is the largest that fits an
int, and 20! the largest that fits along. - Python: an
inthas no limit, so any factorial is exact. - TypeScript: 18! is the largest below
Number.MAX_SAFE_INTEGER. Past that, useBigInt.
- 01
n % 10reads the last digit, and integer division by 10 drops it. One loop of these two takes any number apart. - 02
The loop runs once per digit, so it is O(log n): 10 passes for a 10-digit number.
- 03
Build a reverse with
rev = rev * 10 + digit, and save a copy of the number before the loop eats it. - 04
Check the edges: 0, one digit, negatives, trailing zeros, and results past your language's integer limit.
Read more
- Remainder (%) on MDN, including what it does with negative numbers
- Binary arithmetic operations in the Python reference, for
//and%on negative numbers - Narcissistic number on Wikipedia, the maths name for Armstrong numbers
- Palindrome Number on takeUforward, to solve it yourself
Next: divisors, primes and GCD, where one loop stops at the square root.