数值的整数次方
题目: 输入数字n,按顺序打印出从1到最大的n位十进制数。比如输入3,则打印出1,2,3一直到最大的3位数999.
1. 陷阱
乍一看,似乎很简单,一次循环就能搞定
void PrintToMaxOfNDigits_1(int n)
{
int number=1;
int i=0;
while(i++<n)
number*=10;
for(i=1;i<number;++i)
print("%d\t",i);
}
但是如果再仔细想想,因为没有给定n的范围,所以如果n是个大数,那么无论是 整型(int) 或者 长整型(long long) 还是会溢出。
所以其实这是一个大数问题!
大数问题用什么?
当然是——字符串!
2. 在字符串上模拟数字加法
因为数字最大的是n位,所以我们需要一个长度为n+1的字符串(字符串的最火一位是结束符为 \0),当实际数字不够n为时,在字符串的前半部分补0。
首先把字符串的每一个数字初始化为‘0’。然后每一次为字符串表示的数字加1,再打印出来。因此我们只需要做两件事:一是字符串表达的数字上模拟加法;二是把字符串表达的数字打印出来
根据以上思想,有如下代码:
void PrintToMaxOfNDigits(int n)
{
if(n<=0)
return;
char* number=new char[n+1];
memset(number,'0',n);
number[n]='\0';
while(!Increment(number))
{
PrintNumber(number);
}
delete []number;
}
其中函数Increment表示数字的字符串number上增加1,而函数PrintNumber便是打印number
现在关键是两个函数的书写
a.Increment函数
如何知道什么时候停止number上增加1,即什么时候到了最大的n位数"9999…999",最简单的就是在每次增加之后,都调用strcmp函数比较字符串number和最大的“9999…999”,虽然调用strcmp很简单,答案是对于长度为n的字符串,复杂度为O(n)。
有没有更好的办法?当然,可以看到,只有对“999…999”加1的时候,才会在第一个字符(下标为0)的基础上产生进位。此时就是最大的n位数,此时Increment返回true,循环停止。
代码如下:
bool Increment(char* number)
{
bool isOverflow=false;
int nTakeOver=0;
int nLength=strlen(number);
for(int i=nLength-1;i>=0;i--)
{
int nSum=number[i]-'0'+nTakeOver;
if(i==nLength-1)
nSum++;
if(nSum>=10)
{
if(i==0)
isOverflow=true;
else
{
nSum-=10;
nTakeOver=1;
number[i]='0'+nSum;
}
}
else
{
number[i]='0'+nSum;
break;
}
}
return isOverflow;
}
a.PrintNumber函数
当数字位数不够时,在数字前面补0,但是打印的时候不应该打印出来,所以要在第一个非0的时候才打印
void PrintNumber(char* number)
{
bool isBeginning=true;
int nLength=strlen(number);
for(int i=0;i<nLength;++i)
{
if(isBeginning && number[i]!='0')
isBeginning=false;
if(!isBeginning)
{
printf("%c",number[i]);
}
}
printf("\t");
}
3. 递归让代码更简洁
如果我们在数字前面补0,就会发现n位所有的十进制数其实及时n个从0到9的全排列。也就是说,我们把数字的每一位都从0到9排列一遍,就得到了所有的十进制数。只是在打印的时候,排在前面的0不打印出来就好了
全排列很容易表达,数字的每一位都可能时0~9中的一个数,然后设置下一位,递归的结束条件时我们已经设置了数字的最后的一位。
void PrintToMaxOfNDigits(int n)
{
if(n<=0)
return;
char* number=new char[n+1];
number[n]='\0';
for(int i=0;i<10;++i)
{
number[0]=i+'0';
PrintToMaxOfNDigitdRecursively(number,n,0);
}
delete[] number;
}
void PrintToMaxOfNDigitdRecursively(char* number,int length,int index)
{
if(index==length-1)
{
PrintNumber(number);
return;
}
for(int i=0;i<10;++i)
{
number[index+1]=i+'0';
PrintToMaxOfNDigitdRecursively(number,length,index+1);
}
}
参考书籍:《剑指offer》