题目总结笔记
问题描述
小C发现了一类特殊的整数,他称之为“疯狂整数”。疯狂整数是指只包含数字 '1' 和 '2' 的整数。举个例子,数字 1、2 和 121 都是疯狂整数。
现在,给定一个整数 N,你的任务是计算出所有小于或等于 N 的非负疯狂整数的数量。
测试样例
样例1:
输入:
N = 21
输出:5
样例2:
输入:
N = 50
输出:6
样例3:
输入:
N = 5
输出:2
解题思路
-
特性分析:
- 疯狂整数的数字由 '1' 和 '2' 组成,可以通过递归生成所有可能的组合。
- 数字从 1 和 2 开始,每次扩展时在末尾添加 '1' 或 '2'。
- 递归或迭代可以很好地生成所有满足条件的疯狂整数。
-
方法选择:
-
使用 广度优先搜索 (BFS) 的方法:
- 初始数字从 '1' 和 '2' 开始。
- 不断扩展生成新的数字,直到所有生成的数字都大于 N。
- 统计所有小于或等于 N 的疯狂整数。
-
-
剪枝优化:
- 当生成的数字大于 N 时,可以停止继续扩展,避免不必要的计算。
Java代码实现
import java.util.LinkedList;
import java.util.Queue;
public class Main {
public static int solution(int N) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
queue.offer(2);
int count = 0;
while (!queue.isEmpty()) {
int current = queue.poll();
if (current > N) {
continue;
}
count++;
queue.offer(current * 10 + 1);
queue.offer(current * 10 + 2);
}
return count;
}
public static void main(String[] args) {
System.out.println(solution(21) == 5); // 测试样例 1
System.out.println(solution(50) == 6); // 测试样例 2
System.out.println(solution(5) == 2); // 测试样例 3
}
}
代码解析
-
队列初始化:
- 初始化一个队列,初始值为
1和2,分别表示数字 '1' 和 '2'。
- 初始化一个队列,初始值为
-
BFS 生成数字:
- 每次从队列中取出一个数字
current,如果current > N,停止处理该数字。 - 如果 current≤Ncurrent \leq N,将其计入疯狂整数数量。
- 在数字末尾追加 '1' 或 '2',生成新数字并加入队列。
- 每次从队列中取出一个数字
-
统计并返回:
- 最后返回计数器
count的值,即所有小于或等于 N 的疯狂整数的数量。
- 最后返回计数器
复杂度分析
-
时间复杂度:
- 每个数字扩展时生成两个新数字,生成的数字数量为 O(2^d),其中 d 是 N 的位数。
- 时间复杂度为 O(2^d)。
-
空间复杂度:
- 队列中最多存储 O(2^d) 个数字。
- 空间复杂度为 O(2^d)。
总结
- 本题通过 BFS 方法生成所有满足条件的疯狂整数,并使用剪枝优化降低不必要的计算。
- 代码逻辑清晰,易于扩展,可以适应更大的 N。