面试题17:打印从1到最大的n位数
输入数字n,按顺序打印出从1到最大的n位十进制数。比如输入3,则打印出1,2,3一直到最大的3位数999.
错误方法:
先求出最大的n位数,再用一个循环从1逐个打印。但是当n很大时,我们求最大的n位数用int或long long可能都会溢出。所以我们需要考虑的是大数问题。
常规方法:
用字符串解决大数问题。本题中需要重点解决两大问题:1.字符串表示的大数模拟加法;2.把字符串表达的数打印出来。
字符串表示的大数模拟加法:
- 对于每一个字符串,计算加法都是从个位加1。从字符到int类型的计算方法:number[i] - '0';
- 用局部变量nSum表示每一个上的字符,都等于本位+进位。由nSum是否等于10判断是否需要进位,若是,进位标志nTakeOver=1,nSum所在位变为0。下一次迭代时,下一个位会加上进位。
- 如何判断结束:若最大的数999……99加1,则最高位会变为10,而其他情况都不会在第一个字符上产生进位,所以当加1时发现第一个字符产生了进位,表明已经到了最大的n位数了。
bool Increment(char* number)
{
//是否越界标志
bool isOverflow = false;
//进位符
int nTakeOver = 0;
//number中字符的数量
int nLength = strlen(number);
for (int i = nLength - 1; i >= 0; i--)
{
//nSum表示每一位的计算方法:本位+进位
int nSum = number[i] - '0' + nTakeOver;
//每个number都是从个位加1,直至进位
if (i == nLength - 1)
{
nSum += 1;
}
if (nSum == 10)
{
//若是最高位number[0]为10,表示已经到达最大值了,越界标志置为true
if (i == 0)
isOverflow = true;
//若某位加1后为10,则进位1,本位变0;
else
{
nSum -= 10;
nTakeOver = 1;
number[i] = '0';
}
}
//若nSum结果在0-9之间,正常加1即可
else
{
number[i] = '0' + nSum;
break;
}
}
return isOverflow;
}把字符串表达的数打印出来
前面字符串加法操作时,当数字不够n位时,我们会在数字前面补0,打印的字符串应该删除前面这些0。所以在这个函数里,只有在碰到第一个非零的字符之后才会开始打印。
//删除前缀的0
void PrintNumber(char* number)
{
//number中字符的数量
int nLength = strlen(number);
int zero_end = 0;
while (number[zero_end]=='0'&&zero_end<nLength)
{
zero_end++;
}
for (int i = zero_end; i < nLength; i++)
{
cout << number[i];
}
cout << endl;
}
高级方法:
n位所有十进制数其实就是n个从0到9的全排列,用递归表达。递归结束的条件是我们已经设置好了数字的最后一位。
void Print1ToMaxOfDigits(int n)
{
if (n < 0)
return;
char* number = new char[n + 1];
memset(number, '0', n);
number[n] = '\0';
//从最高位为0-9,剩下的位递归排列
for (int i = 0; i < 10; i++)
{
number[0] = i + '0';
Print1ToMaxOfDigitsRecursively(number, n, 0);
}
delete[] number;
}
void Print1ToMaxOfDigitsRecursively(char* number, int length, int index)
{
//若排列到了最后一位,打印字符串,退出函数。
if (index == length - 1)
{
PrintNumber(number);
return;
}
//递归排列
for (int j = 0; j < 10; j++)
{
number[index + 1] = j + '0';
Print1ToMaxOfDigitsRecursively(number, length, index + 1);
}
}
迭代方法(全代码)
//打印大数,忽略前端的0
void printNumberWithoutZero(vector<int>& number)
{
int len = number.size();
//这里注意:迭代时第一个大数为全0,不用打印出来,直接返回空即可。若不处理,会出现数组越界错误
vector<int> allZero(number.size(), 0);
if (number == allZero)
return;
int j = 0;
while (number[j]==0)
{
++j;
}
for(int i=j;i<len;++i)
cout << number[i];
cout << endl;
}
//递归打印
void Print1ToMaxOfDigit(int n)
{
if (n <= 0)
return;
vector<int> number(n, 0);
for (int i = 0; i <= 9; ++i)
{
number[0] = i;
PrintRecrusively(number,n, 1);
}
}
void PrintRecrusively(vector<int>& number,int n,int index)
{
//若数组下标已经打印到了第n位,因最高位为n-1位,所以可返回
if (index == n)
{
printNumberWithoutZero(number);
return;
}
for (int i = 0; i <= 9; ++i)
{
number[index] = i;
PrintRecrusively(number, n,index + 1);
}
}
int main()
{
int n = 3;
Print1ToMaxOfDigit(n);
return 0;
}
查看26道真题和解析