An integer x
is a good if after rotating each digit individually by 180 degrees, we get a valid number that is different from x
. Each digit must be rotated - we cannot choose to leave it alone.
A number is valid if each digit remains a digit after rotation. For example:
0
, 1
, and 8
rotate to themselves,2
and 5
rotate to each other (in this case they are rotated in a different direction, in other words, 2
or 5
gets mirrored),6
and 9
rotate to each other, andGiven an integer n
, return the number of good integers in the range [1, n]
.
Example 1:
Input: n = 10 Output: 4 Explanation: There are four good numbers in the range [1, 10] : 2, 5, 6, 9. Note that 1 and 10 are not good numbers, since they remain unchanged after rotating.
Example 2:
Input: n = 1 Output: 0
Example 3:
Input: n = 2 Output: 1
Constraints:
1 <= n <= 104
Given an integer n
, find the number of "good" integers in the range [1, n]
. A "good" integer is defined as an integer where after rotating each digit individually by 180 degrees, we get a valid number that is different from the original number. Valid digits after rotation are 0, 1, 8, and the pairs (2, 5) and (6, 9).
Two approaches are presented here: direct enumeration and digit dynamic programming (DP).
This approach iterates through each number from 1 to n
and checks if it's a "good" number. The check involves:
2
maps to 5
, 5
maps to 2
, etc.). Invalid rotations map to -1.Time Complexity: O(n log n) - iterating through n
numbers, and the rotation check takes O(log n) time due to digit processing.
Space Complexity: O(1) - constant extra space is used.
Code (Python):
class Solution:
def rotatedDigits(self, n: int) -> int:
d = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6] # Rotation mapping
def check(x):
y, t = 0, x
k = 1
while t:
v = t % 10
if d[v] == -1:
return False # Invalid rotation
y = d[v] * k + y
k *= 10
t //= 10
return x != y # Different from original
return sum(check(i) for i in range(1, n + 1))
Other languages (Java, C++, Go, TypeScript) would follow a similar structure.
This approach is more efficient for larger values of n
. It uses dynamic programming to count good numbers without explicitly iterating through each number.
The core idea is a recursive function dfs(i, ok, limit)
:
i
: Current digit position (from most significant to least significant).ok
: Boolean indicating if a good digit has been encountered so far (true if at least one rotated digit is different from original).limit
: Boolean indicating whether current digit is constrained by the input number n
.The recursion explores possible digits at each position, considering valid rotations and constraints from n
. The base case is when all digits have been processed.
Time Complexity: O(log n) - the number of digits in n
determines the recursion depth.
Space Complexity: O(log n) - due to recursion depth and potentially memoization.
Code (Python):
class Solution:
def rotatedDigits(self, n: int) -> int:
s = str(n)
@cache # memoization for efficiency
def dfs(i, ok, limit):
if i == len(s):
return ok
up = int(s[i]) if limit else 9
ans = 0
for j in range(up + 1):
if j in (0, 1, 8):
ans += dfs(i + 1, ok, limit and j == up)
elif j in (2, 5, 6, 9):
ans += dfs(i + 1, 1, limit and j == up)
return ans
return dfs(0, 0, True)
Similar code structures can be implemented in other languages (Java, C++, Go, TypeScript) using memoization techniques to optimize performance. The Java and C++ examples explicitly show memoization using arrays or @cache
as appropriate. Other languages may require different memoization approaches based on language features.
While the direct enumeration approach is simpler to understand, digit DP offers significantly better performance for larger inputs. The choice depends on the expected input size and performance requirements.