Math
How to know which math to use
A quick cheat sheet for deducing the right counting logic:
- Use powers (): when every single item makes an independent choice from options. Example: each of merged intervals independently picks one of groups.
- Use combinations (): when you pick a specific number of items from a larger pool and order doesn't matter. Example: "how many ways can you choose exactly 3 intervals out of the total to form a single group?"
- Use permutations (): when you arrange items in a specific sequence. Example: "in what order can these intervals be processed?"
Worked example: 3 intervals, 2 groups
Every interval independently picks group A or B. The choice tree doubles at each level, so the leaf count is .
Change the question and the formula changes with it: "choose exactly 2 of the 3 intervals for group A" is (the leaves with exactly two A's), and "in what order are the 3 intervals processed" is .
Factorials
Trailing zeroes in factorial
A trailing zero is produced by a factor of 10 = 2 * 5. In N! there are always far more factors of 2 than of 5, so the number of trailing zeroes equals the number of factors of 5.
Counting factors of 5 means summing how many multiples of 5, 25, 125, ... are at most N:
fives = N//5 + N//25 + N//125 + ...
Each multiple of 25 contributes a second factor of 5, each multiple of 125 a third, and so on - which is exactly what the running divisor *= 5 captures.
Worked example (N = 100):
100 // 5 = 20100 // 25 = 4100 // 125 = 0- loop stops.- Total trailing zeroes:
24.
- Time
- O(log N)
- The divisor multiplies by
5each iteration, so the loop runs aboutlog_5(N)times. - Space
- O(1)
- Only a few integer accumulators are used.
Digit Counting & Sums
Count Digits in a Number
Peel off one digit at a time with divmod(n, 10), incrementing a counter each pass, until n reaches 0.
- Time
- O(log N)
- The loop runs once per digit of
n, andnhasO(log N)digits. - Space
- O(1)
- Only a counter and the shrinking
nare kept.
Count Commas in Range
Writing a number with thousands separators only inserts a comma once the number reaches 4 digits, i.e. 1000 and up (n's constraints keep every value under a million, so there's never more than one comma). Numbers 1..999 contribute zero commas; every number from 1000 to n contributes exactly one. That's n - 999 numbers, floored at 0.
- Time
- O(1)
- A single subtraction and comparison, no iteration.
- Space
- O(1)
- No auxiliary storage is used.
258. Add Digits
258Add Digits
Same digit-extraction loop as Sum of Digits in Base K: peel off each digit with divmod(num, 10) and accumulate into total. If that single pass didn't reduce num to one digit, recurse on total and repeat until it does.
- Time
- O(log N)
- Each recursive call sums
O(log N)digits, and the digit sum shrinks fast enough that only a handful of recursive calls are ever needed. - Space
- O(log N)
- The recursion stack holds one frame per call until
numcollapses to a single digit.
1837. Sum of Digits in Base K
Same digit-extraction loop as Base 7: peel off the last base-k digit with divmod(n, k) and repeat until n is 0. Instead of collecting digits into an output, just accumulate them into total.
- Time
- O(log N)
- One iteration per base-
kdigit ofn, so the loop runsO(log_k N)times. - Space
- O(1)
- Only a single running total is kept.
3483. Unique 3-Digit Even Numbers
Brute-force over the output space instead of the input: loop every even 3-digit number num from 100 to 998, split it into digits i, j, k, and check whether the multiset {i, j, k} fits inside the available digits.
f = Counter(digits) tallies how many of each digit value are on hand. The membership check relies on booleans being ints in Python (True == 1, False == 0), so each comparison answers "do I still have an unused copy of this digit, after the earlier positions already claimed theirs?"
f[i] > 0needs at least one copy ofi.f[j] > (i == j)needsf[j] > 0normally, but ifjis the same value asi, the threshold becomesf[j] > 1, sinceialready spent one copy of that digit.f[k] > (i == k) + (j == k)needs a threshold of0,1, or2depending on how many ofiandjalready used up that same digit value.num = 777needsf[7] > 0 + 1 + 1 = 2, i.e. three 7s available.
This avoids mutating and restoring a frequency array (f[i] -= 1 ... f[i] += 1) around each check, trading that bookkeeping for the arithmetic trick above.
- Time
- O(1)
- The outer loop always runs over the fixed range of 450 even numbers between 100 and 998, doing O(1) work per iteration, regardless of
len(digits). - Space
- O(1)
- The
Counterholds at most 10 distinct digit keys.
Base Conversion
Decimal to binary
Same digit-extraction loop as Base 7, just base 2 instead of 7: peel off the last bit with divmod(n, 2) and push it to the front of a deque until n is 0.
- Time
- O(log N)
- One iteration per bit of
n, so the loop runsO(log₂ N)times. - Space
- O(1)
- The output deque holds a number of digits proportional to
log₂ N, bounded for any fixed-width integer.
504. Base 7
504Base 7
Same digit-extraction loop as Convert a Number to Hexadecimal, just base 7 instead of 16: peel off the last digit with divmod(num, 7) and push it to the front of a deque until num is 0.
The sign is handled separately: take abs(num) up front, run the loop on the magnitude, then prepend "-" at the end if the original was negative.
- Time
- O(log N)
- One iteration per base-7 digit of
num, so the loop runsO(log₇ N)times. - Space
- O(log N)
resaccumulates one digit per iteration, so it grows toO(log₇ N)size.
405. Convert a Number to Hexadecimal
Peel off the last hex digit of num with divmod(num, 16), map the remainder through hex_arr, and push it to the front of a deque. Repeat until num is 0.
Negative numbers are handled by first converting to their 32-bit two's-complement value (2**32 + num), so the same divmod loop produces the correct unsigned hex digits.
- Time
- O(log N)
- One iteration per hex digit of
num, so the loop runsO(log₁₆ N)times, bounded by 8 for a 32-bit integer. - Space
- O(1)
- The output holds at most 8 hex digits regardless of input size.
3602. Hexadecimal and Hexatrigesimal Conversion
Two conversions, one loop. convert(num, to_base) is the same divmod peel as Base 7 and Convert a Number to Hexadecimal, except the base is inferred from the length of the digit alphabet passed in - len(to_base) is 16 for hexa and 36 for hexatri.
hashmap = {idx: ele for idx, ele in enumerate(to_base)} maps a remainder to its display character, so 10 -> "A" in both alphabets and 35 -> "Z" only in base 36. Since to_base is already a string indexable by position, the dict is just an explicit restatement of to_base[rem].
The answer is convert(n*n, hexa) + convert(n*n*n, hexatri) - the square in base 16 concatenated with the cube in base 36. n >= 1 by the constraints, so the while num loop always runs at least once and never returns an empty string.
- Time
- O(log N)
- One iteration per output digit:
log16(n^2)for the hexadecimal pass pluslog36(n^3)for the hexatrigesimal pass. Building eachhashmapis O(1) (16 and 36 fixed entries). - Space
- O(log N)
- The deque plus the joined result hold
O(log n)characters.
171. Excel Sheet Column Number
columnTitle is a base-26 number where each letter is a digit from 1 to 26 (A = 1, not 0), read most-significant-first.
Build a lookup from letter to its 1-indexed value, then fold left to right: total = total * 26 + col[char]. This is the same digit-rebuild as decimal string-to-int parsing, just with base 26 and a 1-indexed digit value instead of 0-indexed.
- Time
- O(N)
- One pass over the
Ncharacters ofcolumnTitle. - Space
- O(1)
- The
collookup is a fixed 26-entry table, independent of input size.
168. Excel Sheet Column Title
This is base-26, but the digits are 1-indexed (A = 1 ... Z = 26, no digit 0), so a plain divmod(columnNumber, 26) would misalign at multiples of 26. Subtracting 1 first (columnNumber - 1) shifts the range to 0-indexed before dividing, which is the same trick as Excel Sheet Column Number run in reverse.
Peel off the last letter with divmod(columnNumber - 1, 26), push it to the front of a deque, and repeat until columnNumber is 0.
- Time
- O(log N)
- One iteration per letter of the output, so the loop runs
O(log₂₆ N)times. - Space
- O(1)
- The output holds a bounded number of letters regardless of input size (excluding the returned string itself).
Number-to-Text Encoding
12. Integer to Roman
List every Roman value (including the subtractive pairs like 900 -> "CM") from largest to smallest. For each one, divmod(num, value) tells you how many times that symbol fits and what's left over - same digit-extraction shape as Sum of Digits in Base K, just against a table of irregular "bases" instead of a fixed one.
- Time
- O(1)
- The table has a fixed 13 entries, so the loop runs at most 13 times regardless of
num. - Space
- O(1)
- The output has a bounded length (at most 15 characters for any valid input).
13. Roman to Integer
Check the two-character slice s[i:i+2] against a table of the six subtractive pairs ("CM", "CD", "XC", "XL", "IX", "IV") first, consuming 2 characters on a hit. Otherwise fall back to the single-character table and consume 1 - the inverse lookup of Integer to Roman's greedy value-symbol table.
- Time
- O(n)
- Each iteration advances
iby 1 or 2, so the loop visits every character ofsat most once. - Space
- O(1)
- Both lookup tables have a fixed number of entries regardless of
s.
273. Integer to English Words
Peel off num in base-1000 groups with divmod(num, 1000), same digit-extraction loop as Convert a Number to Hexadecimal, just base 1000 instead of 16.
Each 3-digit group is spelled out by getFrom3Digit: hundreds place from direct + "Hundred", then the last two digits handled as either a tens word, an 11-19 irregular from ten2twenty, or a tens + ones combo.
Non-zero groups get a scale word (Thousand/Million/Billion) from pos[idx] based on which group index they came from, then everything collected in a deque (front-to-back = most-significant-first) is joined with spaces.
- Time
- O(log num)
- The
while numloop peels off one base-1000 group per iteration viadivmod(num, 1000), so it runsO(log num)times (base 1000); each iteration does constant work ingetFrom3Digit. - Space
- O(1)
direct,tens,ten2twenty, andposare fixed-size lookup tables, andansholds at most one entry per group - bounded regardless of input, since a 32-bitnumhas at most 4 groups.
Reversal & Palindromes
7. Reverse Integer
Peel off the last digit of n with n % 10 and n // 10, then rebuild the reversed number one digit at a time with res = res * 10 + last_bit.
The sign is handled separately: negate n up front if it was negative, reverse the positive magnitude, then re-apply the sign at the end.
Since Python ints don't overflow, the 32-bit range check -2**31 <= res <= 2**31 - 1 is done explicitly after the loop instead of relying on overflow to happen naturally.
- Time
- O(log N)
- One iteration per digit of
n, so the loop runsO(log N)times. - Space
- O(1)
- Only a handful of integer accumulators are used.
9. Palindrome Number
Same digit-rebuild loop as Reverse Integer: peel off digits of x with divmod(x, 10) and rebuild them in reverse into rev. x is a palindrome exactly when the fully reversed number equals the original.
Negative numbers can never be palindromes (the - only appears at the front), so they're rejected up front.
- Time
- O(log N)
- One iteration per digit of
x, so the loop runsO(log N)times. - Space
- O(1)
- Only
original,x, andrevare tracked.
Power Checks
326. Power of Three
Keep dividing n by 3 as long as it divides evenly. If n really is a power of 3, this whittles it all the way down to 1; if any remainder pops up along the way, it never was.
- Time
- O(log N)
- Each iteration divides
nby 3, so the loop runsO(log₃ N)times. - Space
- O(1)
- Only
nitself is tracked.
1780. Check if Number is a Sum of Powers of Three
n is a sum of distinct powers of 3 exactly when its base-3 representation has no digit 2 - every digit is 0 or 1, i.e. each power of 3 is used at most once. This is the same digit-extraction loop as Sum of Digits in Base K and Base 7, but instead of collecting the digit it just checks it: n % 3 == 2 means a digit is unusable, so bail out immediately.
- Time
- O(log N)
- One iteration per base-3 digit of
n, so the loop runsO(log₃ N)times. - Space
- O(1)
- Only
nitself is tracked.
Range Bookkeeping
598. Range Addition II
Every operation increments a rectangle [0, i) x [0, j) starting at the origin. The cell that ends up with the maximum value is always inside every one of those rectangles, so the answer region is just the intersection of all of them: rows 0 to min(i) and columns 0 to min(j). Track the running minimums a and b across ops and return their product.
- Time
- O(len(ops))
- Each operation is visited once to update the running minimums
aandb. - Space
- O(1)
- Only the scalars
aandbare kept, regardless ofm,n, or the number of operations.