* 面试题17:打印从1到最大的n位数
* 题目:输入数字n,按顺序打印出从1到最大的n位十进制数。
* 比如输入3,则打印出1,2,3一直到最大的3位数999
*
* 思路:考虑大数问题,使用字符串或数组表示
方法一:使用字符串的方式
/*思路:1、先将字符串中的每一个字符都初始化为'0',以便之后若是长度不到n,不必再进行赋'0'值
C语言中:n+1的原因是字符串中有一个结束符‘/0’虽然打印不出来,但是他是必要的
Java语言中:n的原因是字符串不是以‘/0’结束的,因为Java中的一切数据都是对象,对象有自己的属性状态,如length等
* 2、然后每一次将字符串表达式中的数字进行加1
加1时应注意设置一个第一个字符的判溢出标识符,
2-1:对字符串中的每一个字符进行遍历,取其字符转换为int型,然后判断是否为最后一位字符,若为最后一位字符则进行+1
2-2:再判断是否为当前值(这一字符)>=10,
(1)若成立,则判断是否是第1位(也就是i=0),若是则表示第一位进位(溢出了),则返回true
(2)若成立,但是不是第一位字符(i!=0),则表示是其他位向前进位了,则将isOverflow(进位符)设置为1(表示向前进位,下一个字符要加1), 将当前值curNum-10(因为未进行加1操作之前为9,加1后为10,而一位字符不能够存下10两位,所以-10,存0);还要将当前值转换为char型,传回给char型数组的第i位。然后再i--,进行下一个字符的判断
(3)若不成立,表示当前值<10,(也就是当前情况是只是末尾加1或者是最后一个更改的字符位,未对前一位有任何影响)那么直接将值转换为char型并传回数组即可,然后跳出循环即可。返回false 表示未溢出即可
* 3、并将字符串表达式中的数字打印出来
方法二:使用递归的方式
* 思路:在数字前面补0,会发现n位所有十进制数就是n个从0到9的全排列
* 把数字的每一位从0到9排列一遍,就能得到所有的十进制数
* 再打印时不将前面的0打印出来
*
* 递归时,数字的每一位可能是从0到9中的一个属,然后设置下一位
* 使用递归的方式,(00)n为字符串先判断第一个字符,然后嵌套再判断第二个字符,。。。,直到判断完n为字符串之后在进行打印。
* 然后再判断下一个字符串,一点点累加(01),。。。过程同上。每一位都是从0输出到9 ,所以要小于10即可,到达10就结束。
* 因为有n(数组长度)进行限制,所以每一个字符递归几次就有n值决定:
* 比如:n=2,那么在if(index==1)时,递归1次,就会不在递归而是打印出字符串的内容;
* 若n=3,那么在if(index==2)时,递归2次,就会不在递归而是打印出字符串的内容。
package Test;
import java.util.Scanner;
public class No17print1ToMaxOfNDigits {
/*
* 面试题17:打印从1到最大的n位数
* 题目:输入数字n,按顺序打印出从1到最大的n位十进制数。
* 比如输入3,则打印出1,2,3一直到最大的3位数999
*
* 思路:考虑大数问题,使用字符串或数组表示
*
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
No17print1ToMaxOfNDigits p = new No17print1ToMaxOfNDigits();
Scanner in = new Scanner(System.in);
System.out.println("输入要打印的n位数中的n值:");
int n = in.nextInt();
//p.print1ToMaxOfNDigits_1(n);
p.print1ToMaxOfNDigits_2(n);
}
//方法一:使用字符串的方式
/*思路:1、先将字符串中的每一个字符都初始化为'0',以便之后若是长度不到n,不必再进行赋'0'值
* C语言中:n+1的原因是字符串中有一个结束符‘/0’虽然打印不出来,但是他是必要的
* Java语言中:n的原因是字符串不是以‘/0’结束的,因为Java中的一切数据都是对象,对象有自己的属性状态,如length等
* 2、然后每一次将字符串表达式中的数字进行加1
* 加1时应注意设置一个第一个字符的判溢出标识符,
* 2-1:对字符串中的每一个字符进行遍历,取其字符转换为int型,然后判断是否为最后一位字符,若为最后一位字符则进行+1
* 2-2:再判断是否为当前值(这一字符)>=10,(1)若成立,则判断是否是第1位(也就是i=0),若是则表示第一位进位(溢出了),则返回true
* (2)若成立,但是不是第一位字符(i!=0),则表示是其他位向前进位了,则将isOverflow(进位符)设置为1(表示向前进位,下一个字符要加1),
* 将当前值curNum-10(因为未进行加1操作之前为9,加1后为10,而一位字符不能够存下10两位,所以-10,存0)
* 还要将当前值转换为char型,传回给char型数组的第i位。然后再i--,进行下一个字符的判断
* (3)若不成立,表示当前值<10,(也就是当前情况是只是末尾加1或者是最后一个更改的字符位,未对前一位有任何影响)那么直接将值转换为char型并传回数组即可,然后跳出循环即可。返回false 表示未溢出即可
* 3、并将字符串表达式中的数字打印出来
*
*
* */
//打印从1到最大的n位数
public void print1ToMaxOfNDigits_1(int n) {
// TODO Auto-generated method stub
if(n<=0) {
return;
}
char[] number = new char[n];
//
for(int i=0;i<n;i++) {
number[i]='0';
}
//当字符串表达式中的数字未达到99...999时,返回false一直循环,否则,返回true
while(!increment(number)) {
//打印字符串表达式中的数字
printNumber(number);
}
}
//当字符串表达式中的数字未达到99...999时,返回false一直循环,否则,返回true
//注意到只有在99...999再进行加1时,会在第一个字符上产生进位,其他则不会,
//所以只需要看是否第一个字符产生了进位即可,此时返回true
public boolean increment(char[] number) {
// TODO Auto-generated method stub
boolean isOverflow = false; //溢位标识符
int nTakeOver = 0; //进位符
for(int i=number.length-1;i>=0;i--) {
int curNum = number[i]-'0'+nTakeOver;
//number[i]-'0' 表示取第i位字符转换为int型
//并且加nTakeOver进位符(进位符置1时:后一位若是满10,则向前以为进1,),记录第i位的数值
if(i == number.length - 1) {
//若是倒数第一位(末尾),则进行加1
curNum++;
}
if(curNum>=10) {
//若当前取得的单个字符大于等于10
if(i == 0) {
//i值为0,表示为第一位
//意味着第一位为>=10,那也就表示这溢出了,第一个字符产生了进位,则返回true
isOverflow = true;
}
else {
//否则,表示非第一位
curNum = curNum - 10;
nTakeOver = 1; //向前一位进1,进位符置1
number[i]=(char)(curNum+'0');//将当前数值转换为char型赋值给数组i
}
}
else {
//若当前取得的单个字符小于10
number[i] = (char)(curNum+'0');
break;
}
}
return isOverflow;
}
//打印字符串表示中的数字
//因为printf会打印出类似“098”这种,并非我们平常会看到的98.所以新设定一个打印函数
//思路:在碰到第一个非0的字符之后开始打印,直到字符串的结尾
public void printNumber(char[] number) {
// TODO Auto-generated method stub
//非零字符标志位
boolean zeroflag = true;
//从低位到高位进行判断,遇到非零就先将非零标志位设置为false
//然后开始输出即可
for(int i=0;i<number.length;++i) {
if(number[i]!='0'&&zeroflag) {
zeroflag = false;
}
if(!zeroflag)
System.out.print(number[i]);
}
//输出一个就换行
System.out.println();
}
//方法二:使用递归的方式
/*
* 思路:在数字前面补0,会发现n位所有十进制数就是n个从0到9的全排列
* 把数字的每一位从0到9排列一遍,就能得到所有的十进制数
* 再打印时不将前面的0打印出来
*
* 递归时,数字的每一位可能是从0到9中的一个属,然后设置下一位
* 使用递归的方式,(00)n为字符串先判断第一个字符,然后嵌套再判断第二个字符,。。。,直到判断完n为字符串之后在进行打印。
* 然后再判断下一个字符串,一点点累加(01),。。。过程同上。每一位都是从0输出到9 ,所以要小于10即可,到达10就结束。
* 因为有n(数组长度)进行限制,所以每一个字符递归几次就有n值决定:
* 比如:n=2,那么在if(index==1)时,递归1次,就会不在递归而是打印出字符串的内容;
* 若n=3,那么在if(index==2)时,递归2次,就会不在递归而是打印出字符串的内容。
* */
public void print1ToMaxOfNDigits_2(int n) {
// TODO Auto-generated method stub
//n表示数组长度
if(n<=0) {
return ;
}
char[] number = new char[n];
for(int i=0;i<10;i++) {
number[0] = (char) (i + '0');//将int型的i转换为char型
print1ToMaxOfNDigitsRecursively(number,n,0);
//使用递归的方法增加数字
}
}
//递归方式加1 全排列的方式
private void print1ToMaxOfNDigitsRecursively(char[] number, int n, int index) {
// TODO Auto-generated method stub
//n表示数组长度
if(index == (n-1)) {
//123----1为index=0第一个字符
// 2为index=1第二个字符,
// 3为index=2第三个字符,最后一个字符
//若已经检索到最后一个字符,则打印整个数组中的数字
printNumber(number);
return;
}
//若未检索到最后一个字符,则继续检索下一个字符
for(int i=0;i<10;i++) {
number[index+1]=(char) (i+'0'); //将int型的下一个转换为char型
print1ToMaxOfNDigitsRecursively(number,n,index+1);
}
}
}