DeepSeek LintCode 3868 · 混淆数字(二) public int confusingNumber(int n)
这是一个关于LintCode 3868 "混淆数字(二)"的问题。这个题目是计算混淆数字的变体,让我们先理解题目要求,然后提供一个解决方案。
·
这是一个关于LintCode 3868 "混淆数字(二)"的问题。这个题目是计算混淆数字的变体,让我们先理解题目要求,然后提供一个解决方案。
问题理解
混淆数字:当一个数字旋转180度后变成另一个不同的有效数字,则称这个数字为混淆数字。
- 有效数字旋转映射:0→0, 1→1, 6→9, 8→8, 9→9
- 其他数字(2,3,4,5,7)旋转后无效
- 数字旋转后不能以0开头
题目要求:给定一个正整数n,计算从1到n(包含)之间有多少个混淆数字?
解题思路
这是一个典型的DFS/回溯问题,我们需要:
- 生成所有可能的混淆数字(只使用0,1,6,8,9)
- 检查旋转后是否与原数字不同
- 排除旋转后以0开头的数字
- 计数不超过n的数字
代码实现
public class Solution {
/**
* @param n: a integer
* @return: return an integer
*/
public int confusingNumber(int n) {
// 有效数字映射
int[] mapping = {0, 1, -1, -1, -1, -1, 9, -1, 8, 6};
// 用于DFS的数字集合(注意0不能作为首位)
int[] digits = {0, 1, 6, 8, 9};
// 计数器
int[] count = new int[1];
// 从1开始DFS(因为0不是正数,且题目要求从1到n)
dfs(0, n, digits, mapping, count, false);
return count[0];
}
private void dfs(long current, int n, int[] digits, int[] mapping,
int[] count, boolean started) {
// 如果当前数字大于n,返回
if (current > n) {
return;
}
// 如果已经开始构建数字(排除初始的0),检查是否是混淆数字
if (started && current > 0) {
if (isConfusing(current, mapping)) {
count[0]++;
}
}
// 继续构建更大的数字
for (int digit : digits) {
long next = current * 10 + digit;
// 如果当前还没有开始构建,且digit是0,跳过(避免前导0)
if (!started && digit == 0) {
continue;
}
dfs(next, n, digits, mapping, count, true);
}
}
private boolean isConfusing(long num, int[] mapping) {
// 旋转数字
long rotated = 0;
long original = num;
while (num > 0) {
int digit = (int)(num % 10);
rotated = rotated * 10 + mapping[digit];
num /= 10;
}
// 检查是否与原数字不同
return rotated != original;
}
}
优化版本(更高效的DFS)
public class Solution {
private int count = 0;
private int[] mapping = {0, 1, -1, -1, -1, -1, 9, -1, 8, 6};
private int[] digits = {0, 1, 6, 8, 9};
public int confusingNumber(int n) {
// 从各个位数开始DFS
for (int digit : digits) {
if (digit != 0) { // 首位不能是0
dfs(digit, n);
}
}
return count;
}
private void dfs(long num, int n) {
// 剪枝:如果当前数字已经大于n,返回
if (num > n) {
return;
}
// 检查是否是混淆数字
if (isConfusing(num)) {
count++;
}
// 继续添加数字
for (int digit : digits) {
long next = num * 10 + digit;
if (next <= n) {
dfs(next, n);
}
}
}
private boolean isConfusing(long num) {
long rotated = 0;
long original = num;
while (num > 0) {
int digit = (int)(num % 10);
rotated = rotated * 10 + mapping[digit];
num /= 10;
}
return rotated != original;
}
}
算法分析
- 时间复杂度:O(5^k),其中k是n的位数。在最坏情况下,我们需要生成所有由{0,1,6,8,9}组成的数字。
- 空间复杂度:O(k),递归调用栈的深度。
示例验证
假设n=100:
- 有效的混淆数字有:6,9,10,18,19,60,68,69,80,81,89,90,91,98
- 共计14个
关键点说明
-
首位不能是0:数字如"01"旋转后变成"10",但原数字"01"在数学上就是1,这不属于混淆数字的范畴。
-
旋转映射:使用-1表示无效数字,在判断混淆数字时只考虑有效数字组成的数字。
-
DFS构建顺序:从1位数字开始,逐渐构建更长的数字,这样可以保证不会漏掉任何可能的混淆数字。
这个解法可以正确处理n的各种取值,并通过DFS的剪枝来优化性能。
更多推荐




所有评论(0)