788. Rotated Digits
Problem Description
You need to find how many "good" integers exist in the range from 1 to n
.
An integer is considered good if it meets two conditions:
- After rotating each of its digits by 180 degrees, the result is still a valid number
- The rotated number must be different from the original number
When a digit is rotated by 180 degrees:
0
,1
, and8
remain the same (0
→0
,1
→1
,8
→8
)2
and5
swap with each other (2
→5
,5
→2
)6
and9
swap with each other (6
→9
,9
→6
)- All other digits (
3
,4
,7
) become invalid after rotation
For a number to remain valid after rotation, it can only contain the digits 0
, 1
, 2
, 5
, 6
, 8
, 9
. If it contains any other digit, the rotation produces an invalid result.
For example:
69
is a good number because rotating it gives96
, which is valid and different from69
11
is NOT a good number because rotating it gives11
, which is the same as the original34
is NOT a good number because it contains3
and4
, which don't have valid rotations
Given an integer n
, return the count of all good integers in the range [1, n]
.
Intuition
The most straightforward way to solve this problem is to check each number from 1
to n
individually to see if it's a "good" number.
To determine if a number is good, we need to:
- Check if all its digits are valid (can be rotated)
- Build the rotated version of the number
- Compare the rotated version with the original
The key insight is to create a mapping that tells us what each digit becomes after rotation. We can use an array d
where d[i]
represents what digit i
becomes after a 180-degree rotation:
d[0] = 0
(0 stays 0)d[1] = 1
(1 stays 1)d[2] = 5
(2 becomes 5)d[5] = 2
(5 becomes 2)d[6] = 9
(6 becomes 9)d[8] = 8
(8 stays 8)d[9] = 6
(9 becomes 6)- For invalid digits (3, 4, 7), we set
d[i] = -1
To check a number x
, we process it digit by digit from right to left:
- Extract each digit using modulo operation (
t % 10
) - If we encounter an invalid digit (where
d[v] == -1
), the number cannot be rotated properly - Otherwise, we build the rotated number
y
by adding the rotated digit at the appropriate position - After processing all digits, if
x != y
, thenx
is a good number
The reason we build the rotated number from right to left is that it allows us to construct y
in the correct order by multiplying each rotated digit by the appropriate power of 10.
Learn more about Math and Dynamic Programming patterns.
Solution Approach
The solution uses direct enumeration to check each number from 1
to n
and count how many are "good" numbers.
Data Structure:
- An array
d
of length 10 that maps each digit to its rotated counterpart:
Whered = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6]
d[i]
represents what digiti
becomes after rotation. Invalid digits are marked with-1
.
Algorithm Implementation:
-
Main Function (
rotatedDigits
):- Iterate through all numbers from
1
ton
- For each number
i
, callcheck(i)
to determine if it's good - Sum up all the good numbers using
sum(check(i) for i in range(1, n + 1))
- Iterate through all numbers from
-
Check Function (
check
): The function determines if a numberx
is good by:a. Initialize variables:
y = 0
: stores the rotated numbert = x
: temporary variable for processing digitsk = 1
: position multiplier (powers of 10)
b. Process each digit from right to left:
while t: v = t % 10 # Extract rightmost digit if d[v] == -1: # Check if digit is invalid return False y = d[v] * k + y # Build rotated number k *= 10 # Move to next position t //= 10 # Remove processed digit
c. Final validation:
- Return
x != y
to ensure the rotated number is different from the original
Example walkthrough for x = 25
:
- First iteration:
v = 5
,d[5] = 2
,y = 2 * 1 + 0 = 2
,k = 10
- Second iteration:
v = 2
,d[2] = 5
,y = 5 * 10 + 2 = 52
,k = 100
- Result:
y = 52
, which is different fromx = 25
, so it's a good number
Time Complexity: O(n × log n)
where n
is the input number. We check n
numbers, and for each number, we process O(log n)
digits.
Space Complexity: O(1)
as we only use a fixed-size array and a few variables.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through finding all good numbers from 1 to 10.
Setup: We have our rotation mapping array: d = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6]
Checking each number:
-
n = 1:
- Extract digit: 1 → rotates to 1
- Rotated number: 1
- Is 1 ≠ 1? No → NOT good
-
n = 2:
- Extract digit: 2 → rotates to 5
- Rotated number: 5
- Is 2 ≠ 5? Yes → GOOD ✓
-
n = 3:
- Extract digit: 3 → d[3] = -1 (invalid)
- Cannot rotate → NOT good
-
n = 4:
- Extract digit: 4 → d[4] = -1 (invalid)
- Cannot rotate → NOT good
-
n = 5:
- Extract digit: 5 → rotates to 2
- Rotated number: 2
- Is 5 ≠ 2? Yes → GOOD ✓
-
n = 6:
- Extract digit: 6 → rotates to 9
- Rotated number: 9
- Is 6 ≠ 9? Yes → GOOD ✓
-
n = 7:
- Extract digit: 7 → d[7] = -1 (invalid)
- Cannot rotate → NOT good
-
n = 8:
- Extract digit: 8 → rotates to 8
- Rotated number: 8
- Is 8 ≠ 8? No → NOT good
-
n = 9:
- Extract digit: 9 → rotates to 6
- Rotated number: 6
- Is 9 ≠ 6? Yes → GOOD ✓
-
n = 10:
- First digit: 0 → rotates to 0, y = 0
- Second digit: 1 → rotates to 1, y = 1 × 10 + 0 = 10
- Rotated number: 10
- Is 10 ≠ 10? No → NOT good
Result: Good numbers in range [1, 10] are: 2, 5, 6, 9 Count: 4
Detailed trace for n = 25:
- Initialize: y = 0, t = 25, k = 1
- Iteration 1:
- v = 25 % 10 = 5
- d[5] = 2 (valid)
- y = 2 × 1 + 0 = 2
- k = 10, t = 2
- Iteration 2:
- v = 2 % 10 = 2
- d[2] = 5 (valid)
- y = 5 × 10 + 2 = 52
- k = 100, t = 0
- Final check: 25 ≠ 52? Yes → GOOD ✓
Solution Implementation
1class Solution:
2 def rotatedDigits(self, n: int) -> int:
3 """
4 Count how many integers from 1 to n are 'good' numbers.
5 A number is 'good' if after rotating each digit 180 degrees,
6 we get a valid different number.
7
8 Args:
9 n: Upper bound of the range to check
10
11 Returns:
12 Count of good numbers in range [1, n]
13 """
14
15 def is_good_number(number):
16 """
17 Check if a number becomes a valid different number after rotation.
18
19 Args:
20 number: The number to check
21
22 Returns:
23 True if the number is good, False otherwise
24 """
25 rotated_number = 0
26 temp_number = number
27 place_value = 1
28
29 # Process each digit from right to left
30 while temp_number:
31 digit = temp_number % 10
32
33 # If digit cannot be rotated (3, 4, 7), number is invalid
34 if rotation_map[digit] == -1:
35 return False
36
37 # Build the rotated number digit by digit
38 rotated_number = rotation_map[digit] * place_value + rotated_number
39 place_value *= 10
40 temp_number //= 10
41
42 # Number is good if it changes after rotation
43 return number != rotated_number
44
45 # Mapping of each digit to its 180-degree rotation
46 # -1 means the digit cannot be rotated to form a valid digit
47 # Index represents the digit, value represents its rotation
48 rotation_map = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6]
49 # 0 1 2 3 4 5 6 7 8 9
50
51 # Count all good numbers from 1 to n
52 return sum(is_good_number(i) for i in range(1, n + 1))
53
1class Solution {
2 // Mapping array: index represents original digit, value represents rotated digit
3 // -1 means the digit cannot be rotated (invalid)
4 // 0->0, 1->1, 2->5, 3->invalid, 4->invalid, 5->2, 6->9, 7->invalid, 8->8, 9->6
5 private int[] rotationMap = new int[] {0, 1, 5, -1, -1, 2, 9, -1, 8, 6};
6
7 public int rotatedDigits(int n) {
8 int goodNumberCount = 0;
9
10 // Check each number from 1 to n
11 for (int number = 1; number <= n; ++number) {
12 if (isGoodNumber(number)) {
13 ++goodNumberCount;
14 }
15 }
16
17 return goodNumberCount;
18 }
19
20 /**
21 * Checks if a number is "good" after rotation
22 * A number is good if:
23 * 1. All its digits can be rotated (no 3, 4, or 7)
24 * 2. The rotated number is different from the original
25 */
26 private boolean isGoodNumber(int originalNumber) {
27 int rotatedNumber = 0;
28 int tempNumber = originalNumber;
29 int placeValue = 1; // Represents the position multiplier (1, 10, 100, ...)
30
31 // Process each digit from right to left
32 while (tempNumber > 0) {
33 int currentDigit = tempNumber % 10;
34
35 // Check if current digit can be rotated
36 if (rotationMap[currentDigit] == -1) {
37 return false; // Contains invalid digit (3, 4, or 7)
38 }
39
40 // Build the rotated number digit by digit
41 rotatedNumber = rotationMap[currentDigit] * placeValue + rotatedNumber;
42 placeValue *= 10;
43 tempNumber /= 10;
44 }
45
46 // Number is good only if it changes after rotation
47 return originalNumber != rotatedNumber;
48 }
49}
50
1class Solution {
2public:
3 int rotatedDigits(int n) {
4 // Mapping array: index represents original digit, value represents rotated digit
5 // -1 means the digit cannot be rotated (3, 4, 7)
6 // 0->0, 1->1, 2->5, 5->2, 6->9, 8->8, 9->6
7 int digitMapping[10] = {0, 1, 5, -1, -1, 2, 9, -1, 8, 6};
8
9 // Lambda function to check if a number is "good" after rotation
10 auto isGoodNumber = [&](int number) -> bool {
11 int rotatedNumber = 0; // Store the rotated number
12 int originalNumber = number; // Keep a copy of the original number
13 int placeValue = 1; // Track the place value (1, 10, 100, ...)
14
15 // Process each digit from right to left
16 while (originalNumber > 0) {
17 int currentDigit = originalNumber % 10;
18
19 // If current digit cannot be rotated, the number is not valid
20 if (digitMapping[currentDigit] == -1) {
21 return false;
22 }
23
24 // Build the rotated number digit by digit
25 rotatedNumber = digitMapping[currentDigit] * placeValue + rotatedNumber;
26 placeValue *= 10;
27 originalNumber /= 10;
28 }
29
30 // A good number must be different after rotation
31 return number != rotatedNumber;
32 };
33
34 // Count all good numbers from 1 to n
35 int goodNumberCount = 0;
36 for (int i = 1; i <= n; ++i) {
37 if (isGoodNumber(i)) {
38 goodNumberCount++;
39 }
40 }
41
42 return goodNumberCount;
43 }
44};
45
1/**
2 * Counts how many numbers from 1 to n are "good" numbers after rotation
3 * A "good" number is valid when rotated 180 degrees and becomes a different number
4 * @param n - The upper bound to check numbers from 1 to n
5 * @returns The count of good numbers
6 */
7function rotatedDigits(n: number): number {
8 // Mapping of digits to their 180-degree rotated values
9 // -1 means the digit cannot be rotated (invalid)
10 // 0->0, 1->1, 2->5, 5->2, 6->9, 8->8, 9->6
11 const digitRotationMap: number[] = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6];
12
13 /**
14 * Checks if a number is a valid "good" number after rotation
15 * @param num - The number to check
16 * @returns true if the number is valid and different after rotation
17 */
18 const isGoodNumber = (num: number): boolean => {
19 let rotatedNumber = 0;
20 let tempNum = num;
21 let placeValue = 1;
22
23 // Process each digit from right to left
24 while (tempNum > 0) {
25 const currentDigit = tempNum % 10;
26
27 // Check if current digit can be rotated
28 if (digitRotationMap[currentDigit] === -1) {
29 return false;
30 }
31
32 // Build the rotated number from right to left
33 rotatedNumber = digitRotationMap[currentDigit] * placeValue + rotatedNumber;
34 placeValue *= 10;
35 tempNum = Math.floor(tempNum / 10);
36 }
37
38 // A good number must be different after rotation
39 return num !== rotatedNumber;
40 };
41
42 // Create array from 1 to n, filter for good numbers, and return count
43 return Array.from({ length: n }, (_, index) => index + 1)
44 .filter(isGoodNumber)
45 .length;
46}
47
Time and Space Complexity
Time Complexity: O(n * log(n))
The main function iterates through all numbers from 1 to n, which gives us O(n)
iterations. For each number i
, the check
function is called, which processes each digit of the number. The number of digits in a number i
is O(log(i))
, and in the worst case when i = n
, this becomes O(log(n))
. Therefore, the overall time complexity is O(n * log(n))
.
Space Complexity: O(1)
The space complexity is constant because:
- The dictionary
d
is a fixed-size array of 10 elements, which takesO(1)
space - The
check
function uses only a fixed number of variables (y
,t
,k
,v
) regardless of input size - No recursive calls are made, so there's no additional stack space usage
- The sum operation uses constant extra space for accumulation
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrectly Building the Rotated Number
A common mistake is building the rotated number in the wrong order. When processing digits from right to left, developers might accidentally reverse the number or apply rotations incorrectly.
Incorrect approach:
# Wrong: This reverses the number while rotating rotated = 0 while temp: digit = temp % 10 rotated = rotated * 10 + rotation_map[digit] # This reverses! temp //= 10
Correct approach:
# Correct: Maintains digit positions rotated = 0 place_value = 1 while temp: digit = temp % 10 rotated = rotation_map[digit] * place_value + rotated place_value *= 10 temp //= 10
2. Forgetting to Check for Invalid Digits
Some developers might assume all digits can be rotated and forget to handle invalid cases (3, 4, 7).
Incorrect approach:
# Wrong: Assumes all digits are valid rotation_map = [0, 1, 5, 0, 0, 2, 9, 0, 8, 6] # Using 0 for invalid digits # This would incorrectly process numbers like 34 as valid
Correct approach:
# Correct: Explicitly mark invalid digits rotation_map = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6] if rotation_map[digit] == -1: return False
3. Missing the "Different Number" Requirement
A critical mistake is forgetting that good numbers must be different after rotation. Numbers like 11, 88, or 181 rotate to themselves and should NOT be counted.
Incorrect approach:
def is_good_number(number):
# Check only if rotation is valid, not if it's different
while temp:
if rotation_map[digit] == -1:
return False
# ... build rotated number
return True # Wrong: doesn't check if number changed
Correct approach:
def is_good_number(number):
# ... build rotated number
return number != rotated_number # Must be different!
4. Off-by-One Error in Range
Forgetting to include n
in the range or starting from 0 instead of 1.
Incorrect approaches:
# Wrong: Excludes n
sum(is_good_number(i) for i in range(1, n))
# Wrong: Includes 0 (which isn't in the problem range)
sum(is_good_number(i) for i in range(0, n + 1))
Correct approach:
# Correct: Range [1, n] inclusive
sum(is_good_number(i) for i in range(1, n + 1))
5. Integer Overflow in Other Languages
While not an issue in Python, languages like C++ or Java might face integer overflow when building large rotated numbers. Always consider the constraints and use appropriate data types.
Solution for other languages:
- Use
long long
in C++ orlong
in Java when necessary - Check problem constraints to ensure the rotated number fits within integer limits
What are the most two important steps in writing a depth first search function? (Select 2)
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!