易混淆数 II
难度:
标签:
题目描述
代码结果
运行时间: 47 ms, 内存: 16.1 MB
/*
* 题目思路:
* 通过Java Stream API,我们可以使用递归生成所有可能的数字,
* 并使用流的过滤功能来筛选出所有有效的易混淆数。
*/
import java.util.*;
import java.util.stream.*;
public class ConfusingNumberIIStream {
private static final char[] DIGITS = {'0', '1', '6', '8', '9'};
private static final Map<Character, Character> CONFUSING_MAP = Map.of(
'0', '0',
'1', '1',
'6', '9',
'8', '8',
'9', '6'
);
public long confusingNumberII(int N) {
return generateNumbers(0, new StringBuilder())
.filter(num -> num > 0 && num <= N && isConfusingNumber(Long.toString(num)))
.count();
}
private Stream<Long> generateNumbers(long cur, StringBuilder sb) {
if (cur > Integer.MAX_VALUE) return Stream.empty();
Stream<Long> result = Stream.of(cur);
for (char digit : DIGITS) {
if (cur == 0 && digit == '0') continue;
sb.append(digit);
result = Stream.concat(result, generateNumbers(cur * 10 + (digit - '0'), sb));
sb.deleteCharAt(sb.length() - 1);
}
return result;
}
private boolean isConfusingNumber(String num) {
StringBuilder rotated = new StringBuilder();
for (char c : num.toCharArray()) {
rotated.append(CONFUSING_MAP.get(c));
}
return !num.equals(rotated.reverse().toString());
}
}
解释
方法:
这道题目要求找到不超过给定数字 n 的所有'易混淆数'的数量。'易混淆数'是指当一个数字旋转 180 度后,形成一个不同的有效数字。题解中定义了两个方法:confusingNumberIII 和 confusingNumberII。
confusingNumberIII 方法遍历从 1 到 n 的所有数字,首先将包含不可翻转的数字(2, 3, 4, 5, 7)的数字排除。然后,将剩余的数字进行转换:6 和 9 互换,最后将数字翻转。如果翻转后的数字与原数字不同,则是一个易混淆数。
confusingNumberII 方法使用了一种生成方法来直接构造可能的易混淆数,并且计算它们的数量。通过固定数字的一半长度,然后生成所有可能的组合,并将它们翻转拼接来形成完整的数字。然后根据生成的数字是否有效和是否大于 n 来决定是否停止。这种方法更有效地使用了数位的特性来直接计算易混淆数的数量。
时间复杂度:
confusingNumberIII: O(n * k), confusingNumberII: O(5^L)
空间复杂度:
confusingNumberIII: O(k), confusingNumberII: O(L)
代码细节讲解
🦆
在`confusingNumberIII`方法中,为什么选择通过字符串操作来检测数字是否为易混淆数,而不是直接使用数学运算?
▷🦆
在`confusingNumberII`方法中,如何确保生成的数字不会重复计算,并且如何处理大于n的情况?
▷🦆
对于`confusingNumberII`方法中的异常处理(`raise ValueError()`),这种方式在什么情况下会触发,以及为什么选择使用异常来控制流程?
▷🦆
在`confusingNumberII`方法中,为什么在数字的最后一位使用6或9的时候,需要特别处理奇数长度的数字串?
▷