- 输入数字n,按顺序打印处1到最大的n位十进制数,比如输入3,则打印1~999之间的数
思路一:如果直接按照数字循环输出的话,可能会遇到大数问题。
代码如下:
/**
* 边界
* 这种情况可能存在大数问题,通过字符串去解决大数问题
* @param n
*/
public static void printFrom1ToMaxOfNDigit(int n) {
if (n <=0){
return;
}
int max = (int) Math.pow(10,n)-1;
for (int i=1;i <= max;i++){
System.out.println(i);
}
}
思路二:使用数组模拟以避免大数问题
创建一个大小为n的数组,while给每次num数组形成的值加1,如果溢出则不再继续加1,每次输出加1后从不为0的数开始的值。
加1操作的实现在于,for循环从最后一位开始,给数组每次调用都会加1,如果没有产生进位,则直接将相应位置的数字加1并终止循环,返回false;如果产生进位(即记录的上个累加和大于等于10,因为number[i]不能大于9,所以通过记录累加和的方式,判断是否需要进位)分为两种情况,第一种是进位到第一位直接返回true,如果只是累加和大于等于10,则将累加和归0,数组当前位归0。
打印操作用for循环可以设置一个标志位,只有当前数组中的数值不为0时,改动标志位才正式开始打印。同时因为多次调用,执行完毕后输出换行。
代码如下:
/**
*用数组表示大数
* @param n
*/
public static void printFrom1ToMaxOfNDigit_1(int n) {
if (n <=0){
return;
}
int[] number = new int[n];
while(!increment(number,n)){
printNumber(number);
}
}
private static void printNumber(int[] number) {
int len = number.length;
boolean isStart = false;
for (int i=0;i<len;i++){
if (!isStart && number[i] != 0){
isStart = true;
}
if (isStart){
System.out.print(number[i]);
}
}
System.out.println();
}
private static boolean increment(int[] number, int n) {
boolean isOverflow = false;
int nTakeOver = 1;
for (int i=n-1;i>=0;i--){
//因为number[i]不能大于9,所以通过记录累加和的方式,判断是否需要进位
int sum = number[i] + nTakeOver;
// if (i == n-1){
// sum++;
// }
//超过10
if (sum >= 10){
if (i == 0){
isOverflow = true;
}else{
sum-=10;
number[i] = sum;
}
}else {
number[i]++;
break;
}
}
return isOverflow;
}
/**
*用字符串表示大数
* @param n
*/
public static void printFrom1ToMaxOfNDigit_2(int n) {
if (n <=0){
return;
}
StringBuilder sb = new StringBuilder();
for (int i=0;i<n;i++){
sb.append('0');
}
while(!increment1(sb,n)){
printNumber1(sb);
}
}
private static void printNumber1(StringBuilder sb) {
boolean isStart = false;
for (int i=0;i<sb.length();i++){
if (sb.charAt(i) != '0' && !isStart){
isStart = true;
}
if (isStart){
System.out.print(sb.charAt(i));
}
}
System.out.println();
}
private static boolean increment1(StringBuilder sb, int n) {
boolean isOverFlow = false;
int Take = 1;
for (int i=n-1;i>=0;i--){
//将字符-'0'转换为字符串,再转换为整数
int sum = sb.charAt(i)-'0' + Take;
if (sum >= 10){
if (i==0){
isOverFlow = true;
}else {
sum-=10;
sb.setCharAt(i,'0');
}
}else {
//将整数转换为字符串,在转换为字符
sb.setCharAt(i, (char)(sum+'0'));
break;
}
}
return isOverFlow;
}
思路三:
由于数字的每一位都由0到9构成,所以从第一位开始将每一位依次设置为0-9之中的一位,因为每一位以及以后每一位设置都是一样的,所以采用递归,递归索引从0开始递归,传入一个数组,如果索引的值为数组的长度,则打印数组,跳出方法,否则依次给该索引位置设置0到9不同的值,并递归调用到下一位索引位置。
代码如下:
public static void printFrom1ToMaxOfNDigit_3(int n){
if (n<=0){
return;
}
int[] number = new int[n];
//递归计算从-1开始,因为递归过程是从index+1正式开始
printFrom1ToMaxOfNDigitRecursive(number,n,0);
}
private static void printFrom1ToMaxOfNDigitRecursive(int[] number, int length, int index) {
//终止条件到最后一位
if (index == length){
printNumber(number);
return;
}
for (int i=0;i<10;i++){
number[index] = i;
printFrom1ToMaxOfNDigitRecursive(number,length,index+1);
}
}