The Rotated Digits problem asks: Given a positive integer N
, count how many numbers in the range 1
to N
(inclusive) are "good" after being rotated 180 degrees.
A number is good if, after rotating each of its digits by 180 degrees, it becomes a valid and different number.
0, 1, 2, 5, 6, 8, 9
3, 4, 7
(if any of these are present, the number is not good)0, 1, 8
remain the same after rotation2 <-> 5
and 6 <-> 9
change to each other
Example: For N = 10
, the good numbers are 2, 5, 6, 9
(since they change to 5, 2, 9, 6 respectively).
To solve this problem, we first need to identify which digits are valid when rotated, and which digits cause the number to become invalid. We also need to make sure that the number actually changes after rotation (so numbers made up only of 0, 1, 8
are not counted, since they look the same).
The brute-force approach is to check every number from 1
to N
:
N
.
To optimize, we can use properties of digits and possibly precompute results for all numbers up to N
, or use dynamic programming to avoid repeating work.
Let's break down the solution step-by-step:
0, 1, 2, 5, 6, 8, 9
2, 5, 6, 9
(these digits become different digits after rotation)1
to N
, process all its digits.3, 4, 7
), skip this number.2, 5, 6, 9
), mark the number as "good".N
, we can use a DP array where dp[i]
stores the state for number i
:0
: invalid number (contains invalid digits)1
: valid but not good (only contains 0, 1, 8
)2
: good number (contains at least one changing digit)dp[i]
from dp[i // 10]
and the last digit.This approach is efficient because it avoids recomputing for overlapping subproblems, and only checks each digit a fixed number of times.
Let's take N = 10
and walk through the numbers:
So, for N = 10
, the good numbers are 2, 5, 6, 9
. The answer is 4.
Brute-force approach:
N
, we check each digit (up to log10(N) digits per number).N+1
to store the state of each number.
The DP approach is faster for large N
because it avoids redundant digit checks.
The Rotated Digits problem is about counting numbers between 1
and N
that remain valid and change to a different number when each digit is rotated 180 degrees. By carefully checking each digit and using dynamic programming to store intermediate results, we can efficiently solve the problem for large N
. The key insight is to distinguish between digits that are valid, those that cause a change, and those that make a number invalid, and to use this information to build up the solution efficiently.
class Solution:
def rotatedDigits(self, N: int) -> int:
# 0: invalid, 1: valid but unchanged, 2: good (valid and changes)
dp = [0] * (N + 1)
count = 0
for i in range(1, N + 1):
a, b = dp[i // 10], dp[i % 10]
if a == 0 and i >= 10:
dp[i] = 0
elif b == 0:
dp[i] = 0
elif a == 1 and b == 1:
dp[i] = 1
else:
dp[i] = 2
if dp[i] == 2:
count += 1
return count
class Solution {
public:
int rotatedDigits(int N) {
vector<int> dp(N + 1, 0);
int count = 0;
for (int i = 1; i <= N; ++i) {
int a = dp[i / 10], b = dp[i % 10];
if (i >= 10 && a == 0) {
dp[i] = 0;
} else if (b == 0) {
dp[i] = 0;
} else if (a == 1 && b == 1) {
dp[i] = 1;
} else {
dp[i] = 2;
}
if (dp[i] == 2) ++count;
}
return count;
}
};
class Solution {
public int rotatedDigits(int N) {
int[] dp = new int[N + 1];
int count = 0;
for (int i = 1; i <= N; ++i) {
int a = dp[i / 10], b = dp[i % 10];
if (i >= 10 && a == 0) {
dp[i] = 0;
} else if (b == 0) {
dp[i] = 0;
} else if (a == 1 && b == 1) {
dp[i] = 1;
} else {
dp[i] = 2;
}
if (dp[i] == 2) count++;
}
return count;
}
}
var rotatedDigits = function(N) {
let dp = new Array(N + 1).fill(0);
let count = 0;
for (let i = 1; i <= N; ++i) {
let a = dp[Math.floor(i / 10)], b = dp[i % 10];
if (i >= 10 && a === 0) {
dp[i] = 0;
} else if (b === 0) {
dp[i] = 0;
} else if (a === 1 && b === 1) {
dp[i] = 1;
} else {
dp[i] = 2;
}
if (dp[i] === 2) count++;
}
return count;
};