剑指Offer面试题(第十二天)面试题17

     * 面试题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);
		}
		
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值