这个题解使用了记忆化搜索的思路。通过递归函数 f(i, has_mir, is_limit, is_num) 来搜索所有可能的好数,其中参数含义如下:
- i 表示当前搜索的数字位置
- has_mir 表示之前的数字中是否包含 2/5/6/9
- is_limit 表示当前是否受到了 N 的约束
- is_num 表示当前是否搜索到了一个合法数字
搜索过程中,依次枚举当前位置可能的数字,递归搜索下一个位置。如果枚举的数字合法,则更新 has_mir 状态;如果当前已经搜索到最后一位,则根据 is_num 和 has_mir 的状态来判断是否找到一个好数。
通过记忆化搜索避免了重复计算,最终可以高效地找到 1 到 N 中所有的好数。
时间复杂度: O(logN)
空间复杂度: O(logN)
class Solution:
def rotatedDigits(self, n: int) -> int:
s = str(n)
m = len(s)
# 合法情况:包含至少一个 [2, 5, 6, 9] 且 不包含 [3, 4, 7]
nums = [0, 0, 1, -1, -1, 1, 1, -1, 0, 1]
@lru_cache(None)
def f(i, has_mir, is_limit, is_num):
# 如果已搜索到最后一位,根据状态返回结果
if i == m: return int(is_num and has_mir)
# 如果当前未搜索到合法数字,则跳过当前位,继续搜索下一位
res = 0 if is_num else f(i + 1, has_mir, False, False)
# 根据是否受到 N 的约束,确定枚举的起始数字 lo 和最大数字 hi
lo, hi = 0 if is_num else 1, int(s[i]) if is_limit else 9
# 枚举当前位的数字 j
for j in range(lo, hi + 1):
# 如果数字 j 合法
if nums[j] != -1:
# 递归搜索下一位,同时更新状态
res += f(i + 1, has_mir or nums[j] == 1, is_limit and j == hi, True)
return res
# 调用递归函数,初始状态为:位置 0,之前没有合法数字,受到 N 的约束,当前未搜索到合法数字
return f(0, False, True, False)