Max Difference You Can Get From Changing an Integer: Greedy Digit Replacement
You are given an integer num. You will apply the following steps exactly two times: pick a digit x (0-9) that appears in the number, pick another digit y (0-9), and replace all occurrences of x with y in the number. The resulting number must not contain leading zeros and must not become 0. You perform this operation once to create a number a and once to create a number b. Return the maximum value of a - b.
This is LeetCode 1432: Max Difference You Can Get From Changing an Integer, a medium problem that tests your ability to think greedily about digits. The trick is figuring out the best digit to replace for both the maximum and minimum versions of the number.
Why this problem matters
Digit manipulation problems show up often in interviews, and they test a specific flavor of greedy thinking. Instead of choosing from a set of items or scheduling tasks, you are reasoning about how individual digits affect the magnitude of a number. The leftmost digit has the most impact, so greedy decisions start there. This same "most significant position first" reasoning appears in problems like Remove K Digits, Monotone Increasing Digits, and Largest Number.
The key insight
You need to make two separate numbers: one as large as possible (high) and one as small as possible (low).
To maximize: scan the digits left to right and find the first digit that is not already 9. Replace every occurrence of that digit with 9. This pushes the number as high as it can go, because you are boosting the most significant non-9 digit and all its copies.
To minimize: this is where it gets more nuanced due to the leading zero constraint.
- If the first digit is not
1, replace all occurrences of the first digit with1. This makes the leading digit as small as possible without creating a leading zero. - If the first digit is already
1, scan the remaining digits for the first one that is not0and not1. Replace all occurrences of that digit with0. You skip0and1because replacing a0does nothing useful, and replacing a1with0would turn the leading1into a leading0.
The solution
def max_diff(num: int) -> int:
s = str(num)
# Build the high number
for d in s:
if d != '9':
high = int(s.replace(d, '9'))
break
else:
high = num
# Build the low number
if s[0] != '1':
low = int(s.replace(s[0], '1'))
else:
for d in s[1:]:
if d != '0' and d != '1':
low = int(s.replace(d, '0'))
break
else:
low = num
return high - low
Here is what each section does:
- Convert the number to a string so you can scan and replace individual digits.
- High number: walk through the digits. The first digit that is not
9becomes the target. Replace all of its occurrences with9. If every digit is already9, the high number is justnumitself. - Low number: check the leading digit. If it is not
1, replace all of its occurrences with1. If it is already1, scan the remaining digits for the first one that is neither0nor1, and replace all of its occurrences with0. If no such digit exists (the number is already all1s and0s), the low number isnum. - Return
high - low.
The minimize logic is trickier than the maximize logic because of the leading zero constraint. When the first digit is 1, you cannot just replace the next non-zero digit with 0 blindly. You have to skip 1s too, because str.replace is global. Replacing 1 with 0 would turn the leading 1 into 0, giving you a number with a leading zero (or the number 0 itself).
Visual walkthrough
Step 1: Understand the operation
You pick a digit x and a digit y, then replace every occurrence of x with y. You do this twice: once to build the high number, once to build the low number.
Step 2: Build the high number (maximize)
Scan left to right. The first digit that is not 9 becomes x. Replace all x with 9. For 555, the first digit (5) is not 9, so replace all 5s with 9. Result: 999.
Step 3: Build the low number (minimize)
The first digit is 5 (not 1), so replace all 5s with 1. Result: 111. If the first digit were already 1, we would look at the next digit that is not 0 or 1 and replace it with 0.
Step 4: A trickier example with num = 1101057
First digit is already 1, so we cannot replace s[0]. Scan right: s[1]=1 (skip), s[2]=0 (skip, it is already 0), s[3]=1 (skip), s[4]=0 (skip), s[5]=5 (not 0 or 1). Replace all 5s with 0. Low = 1101007.
Step 5: Compute the difference
Subtract the low number from the high number. For num = 555: high = 999, low = 111, answer = 888.
Let's trace through num = 555 step by step. The string representation is "555".
For the high number, the first digit is 5, which is not 9. Replace all 5s with 9 to get 999.
For the low number, the first digit is 5, which is not 1. Replace all 5s with 1 to get 111.
The difference is 999 - 111 = 888.
Now consider a trickier case: num = 1101057. The first digit is already 1, so you cannot just replace it. Scan the remaining digits: 1 (skip), 0 (skip, it is already 0), 1 (skip), 0 (skip), 5 (this is our target). Replace all 5s with 0 to get 1101007. For the high number, 1 is not 9, so replace all 1s with 9 to get 9909057. The answer is 9909057 - 1101007 = 8808050.
Complexity analysis
| Approach | Time | Space |
|---|---|---|
| Greedy digit replacement | O(d) | O(d) |
Where d is the number of digits. Converting to a string takes O(d), scanning for the target digit takes O(d), and str.replace takes O(d). You do this twice (once for high, once for low), but that is still O(d) overall. Space is O(d) for the string representation.
The building blocks
1. Greedy maximization by digit replacement
The pattern of scanning left to right and modifying the most significant position first is a core greedy strategy for number-building problems:
for digit in number_string:
if digit != target_value:
replace_all(digit, target_value)
break
The leftmost non-optimal digit has the biggest impact on the total value. Fixing it first is always the right greedy choice. You see this same idea in Remove K Digits (remove the leftmost digit that breaks monotonicity) and Monotone Increasing Digits (find the leftmost violation and cascade downward).
2. Greedy minimization with leading zero avoidance
When minimizing a number by replacing digits, you face a constraint that does not exist when maximizing: the result cannot have a leading zero. This forces a two-case analysis:
if first_digit != min_safe_value:
replace_first_digit_with(min_safe_value)
else:
find_next_replaceable_digit_and_zero_it()
The "leading zero avoidance" pattern comes up any time you need to produce a valid number from digit-level operations. Recognizing it quickly saves you from subtle bugs.
Edge cases
Before submitting, make sure your solution handles these:
- Single digit
num = 8: high = replace8with9=9. Low = replace8with1=1. Answer =8. - All same digits
num = 555: high =999, low =111. Answer =888. - Already all 9s
num = 999: high stays999. For low, first digit is9(not1), so replace all9s with1=111. Answer =888. - Leading 1 with all 0s and 1s
num = 10100: high = replace1with9=90900. For low, first digit is1, and scanning the rest gives only0s and1s, so low stays10100. Answer =90900 - 10100 = 80800. - Number is 10
num = 10: high = replace1with9=90. Low = first digit is1, scan rest, find0but it is already0, so low =10. Answer =80.
From understanding to recall
You have read through the greedy digit replacement strategy and the two-case minimize logic. It makes sense. But the tricky part is remembering the minimize edge case during an interview: when the first digit is already 1, you need to skip both 0s and 1s while scanning for the target digit. That detail is easy to forget if you have not practiced it.
Spaced repetition closes that gap. You practice writing the two-case minimize logic from scratch at increasing intervals. After a few rounds, you do not need to re-derive the edge cases. You see "maximize minus minimize with digit replacement" and the code flows out, constraints and all.
The greedy digit strategy is one of roughly 60 reusable building blocks that cover hundreds of LeetCode problems. Learning them individually and drilling them with spaced repetition is far more effective than grinding random problems and hoping they stick.
Related posts
- Reverse Integer - Another digit manipulation problem where you work with individual digits
- Palindrome Number - Working with digit-level representations to check properties
- Remove K Digits - Greedy digit removal to minimize a number
CodeBricks breaks the max difference LeetCode problem into its greedy digit replacement and leading zero avoidance building blocks, then drills them independently with spaced repetition. You type each piece from scratch until the pattern is automatic. When a digit manipulation question shows up in your interview, you do not think about it. You just write it.