PS:《剑指offer》是很多同学找工作都会参考的一本面试指南,同时也是一本算法指南(为什么它这么受欢迎,主要应该是其提供了一个循序渐进的优化解法,这点我觉得十分友好)。现在很多互联网的算法面试题基本上可以在这里找到影子,为了以后方便参考与回顾,现将书中例题用Java实现(第二版),欢迎各位同学一起交流进步。
GitHub: https://github.com/Uplpw/SwordOffer。
完整题目链接: https://blog.csdn.net/qq_41866626/article/details/120415258
1 题目描述
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
leetcode链接: 打印从1到最大的n位数(以下代码已测试,提交通过)
2 测试用例
一般是考虑功能用例,特殊(边缘)用例或者是反例,无效测试用例这三种情况。甚至可以从测试用例寻找一些规律解决问题,同时也可以让我们的程序更加完整鲁棒。
(1)功能用例:正常的n值,如1,2。
(2)边缘用例:n值较大使得 int、long类型无法存储数据,如100。
(3)无效用例:n为0,负数。
3 思路
分析:
此题没有说不需要考虑大数问题,所以是需要考虑的。这样就不能直接用常规的方法来做。
下面是两种思路的具体过程。
解法1:使用字符串模拟数字的加法
一般大数问题都可以转换为字符串的操作。
- 计算位数为n的整数个数k,并创建大小位k字符数组。
- 做循环加法,当没有计算到最后一个数字,返回true,此时记录当前字符数组情况,否则返回false。
- 最后返回字符数组的所有记录即可。
解法2:递归求解(n位数字的全排列)
- 从最高位开始,循环逐步加1(直到9),然后开始递归低位。
- 当递归到最低位,返回输出当前值。
4 代码
算法实现:
public class Print1ToMaxOfNDigits {
// 解法1:使用字符串模拟数字的加法
public static int[] printNumbers(int n) {
if (n <= 0) {
return new int[0];
}
// 计算位数为n的整数个数
int length = 0;
for (int i = 1; i <= n; i++) {
length = length * 10 + 9;
}
char[] array = new char[n];
for (int i = 0; i < n; i++) {
array[i] = '0';
}
// 记录字符数组情况
int[] temp = new int[length];
int index = 0;
while (increase(array)) {
temp[index++] = print(array);
}
return temp;
}
// 模拟加法
public static boolean increase(char[] array) {
for (int i = array.length - 1; i >= 0; i--) {
// 字符不是9,字符加1
if (array[i] < '9' && array[i] >= '0') {
array[i] = (char) ((int) array[i] + 1);
return true;
// 字符是9 当前字符改为0,进入下次for循环
} else if (array[i] == '9') {
array[i] = '0';
} else {
return false; // 无效字符
}
}
// 最高位加法完成,循环结束
return false;
}
// 解法1与解法2共用:返回字符数组代表的数字
public static int print(char[] array) {
int count = 0;
for (int i = 0; i < array.length; i++) {
count = count * 10 + (int) (array[i] - '0');
}
return count;
}
// 解法2:递归解法
public static int[] printNumbersRecursionly(int n) {
if (n <= 0) {
return new int[0];
}
char[] array = new char[n];
for (int i = 0; i < n; i++) {
array[i] = '0';
}
// 记录字符数组情况
int length = 0;
for (int i = 1; i <= n; i++) {
length = length * 10 + 9;
}
int[] result = new int[length];
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
// 最高位逐步加1,然后递归低位
array[0] = (char) ('0' + i);
printNumbersCoreRecursionly(array, n, 0, list);
}
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
return result;
}
public static void printNumbersCoreRecursionly(char[] array, int n, int index, List<Integer> list) {
// 递归到最低位 开始打印
if (index == n - 1) {
int current = print(array);
if (current != 0) {
list.add(current);
}
return;
}
for (int i = 0; i < 10; i++) {
// 当前位逐步加1,再次递归低位
array[index + 1] = (char) ('0' + i);
printNumbersCoreRecursionly(array, n, index + 1, list);
}
}
public static void main(String[] args) {
printNumbers(2);
printNumbersRecursionly(2);
}
}
参考
在解决本书例题时,参考了一些大佬的题解,比如leetcode上的官方、K神,以及其他的博客,在之后的每个例题详解后都会给出参考的思路或者代码链接,同学们都可以点进去看看!
本例题参考:
https://www.jianshu.com/p/71c20c0a44b5
本文如有什么不足或不对的地方,欢迎大家批评指正,最后希望能和大家一起交流进步、拿到心仪的 offer !!!