题目描述:
输入数字n,按顺序打印出从1到最大的n位十进制数,比如输入3,则打印出1,2,3一直到最大的3位数即999
跳进面试官的陷阱:
这个题目看起来很简单。我们看到这个问题后,最容易想到的办法是求出最大的n位数,然后用一个循环从1开始逐个打印。于是我们很容易写出下面的代码。
public static void print1ToMaxOfNDigits(int n) {
int number = (int) Math.pow(10, n);
for (int i = 1; i < number; ++i)
System.out.println(i);
}
初看之下没有问题,但如果仔细分析这个问题,我们就能注意到面试官没有规定n的范围。当输入n很大的时候,我们求最大的n位数是不是用整型(int)或者长整型(long)都会溢出?也就是说我们需要考虑大数问题。这是面试官在这道题里设置的一个大陷阱。
在数组上模拟数字加法的解法,绕过陷阱才能拿到offer:
经过前面的分析,我们很自然的想到解决这个问题需要一个大数。最常用的也是最容易的用字符串或者数组表达大数。接下来我们用数组来解决大数问题。
代码如下:
/**
* 打印从1到最大的n位数:使用数组表示大数
*/
public class PrintOneToMaxNthDigits1 {
// 使用数组实现对数进行+1操作
public static boolean increment(int[] number) {
// 最高位产生进位标志
boolean isOverFlow = false;
// 进位位
int carry = 0;
for (int i = number.length - 1; i >= 0; i--) {
int sum = number[i] + carry;
if (i == number.length - 1) {
sum++;
}
if(sum >= 10){
if(i == 0)
isOverFlow = true;
else{
sum = sum - 10;
carry = 1;
number[i] = sum;
}
}else{
number[i]++;
break;
}
}
return isOverFlow;
}
// 打印数组中表示的数,如果数组中表示的数字位数小于n,则不打印前面的0
public static void print(int[] number) {
// 标记:判断是否可以开始打印
boolean isBeginning = false;
for (int i = 0; i < number.length; i++) {
if (!isBeginning && number[i] != 0) {
isBeginning = true;
}
if (isBeginning)
System.out.print(number[i]);
}
System.out.println();
}
public static void main(String[] args) {
//使用数组来模拟大数
int[] number = new int[3];
while(!increment(number)){
print(number);
}
}
}
Increment要注意终止条件
打印函数:要注意处理前面的‘0’字符
把问题转化成数值排列的解法,递归让代码更简洁:
用数字排列的方法表示:如果我们在数字前面补0的话,就会发现n位所有十进制数其实就是n个从0到9的全排列。也就是说,我们把数字的每一位都从0到9排列一遍,就得到了所有的十进制数。当然打印的时候,我们应该将前面的0补位去掉。
代码如下:
/**
* 打印从1到n位的最大数:使用递归实现全排列
*/
public class PrintOneToMaxNthDigits2 {
//打印数
public void printNumber(StringBuffer sb){
boolean flag = false;
for(int i = 0; i < sb.length(); i++){
if(!flag && sb.charAt(i) != '0'){
flag = true;
}
if(flag){
System.out.print(sb.charAt(i));
}
}
if(flag)
System.out.println();
}
//打印从1到n位的最大数
public void Print1ToMaxOfNDigits(int n){
if(n <= 0)
return ;
//初始化数字(用StringBuffer表示)
StringBuffer sb = new StringBuffer(n);
for(int i = 0; i < n; i++){
sb.append('0');
}
print1ToMaxOfNDigits_Recursely(sb, n, 0);
}
public void print1ToMaxOfNDigits_Recursely(StringBuffer sb, int n, int index){
if(index == n){
printNumber(sb);
return ;
}
for(int i = 0; i < 10; i++){
sb.setCharAt(index, (char)(i+'0'));
print1ToMaxOfNDigits_Recursely(sb, n, index+1);
}
}
public static void main(String[] args) {
PrintOneToMaxNthDigits2 test = new PrintOneToMaxNthDigits2();
test.Print1ToMaxOfNDigits(3);
}
}