题目:输入数字n,按顺序打印出从1到最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。
详细可参考《剑指Offer》面试题12,P94。
本题重点是n的位数不确定,因而用一般的数字类型去存储会溢出,需要考虑大数问题。解决大数问题一般采用字符串或数组来表示大数,这里使用字符串。
思路一:
字符串每个数字都初始化为‘0’,然后每一次让字符串表示的数字加1,再打印出来。
#include <iostream>
using namespace std;
// false: 代表整个n位数已达最大数
bool IncreaseNumber(char *number)
{
bool isOverflow = false;
int flag = 0; // 进位标志
int length = strlen(number);
for (int i = length - 1; i >= 0; --i)
{
int num = number[i] - '0' + flag; // 每次函数调用number[i]的值已经变化,依次是0~9
if (i == length - 1) num++; // 如果是个位,直接加1
if (num >= 10)
{
// 需要进位
if (i == 0) // 如果是第一位(即最高位),若进位,说明已经达到最大数
{
isOverflow = true;
}
else
{
num -= 10; // num继续恢复到0,方便下一位从0开始
flag = 1; // 进位,使下一位的开始值从0变为1
number[i] = num + '0'; // 该句之后,for循环跳到字符串的下一位,本位上依旧要从0开始,相当于个位恢复到0,下次for循环从十位开始
}
}
else // 该位数字在10以内,不需要进位
{
number[i] = num + '0';
break;
}
}
return isOverflow;
}
void PrintNumber(const char* number)
{
// 注意打印输出时以字符逐个输出,011要输出成11
bool isBegin0 = true; // 是否以0开头,默认为true
int length = strlen(number);
for (int i = 0; i < length; ++i)
{
if (isBegin0 && number[i] != '0') // 如果开头不是0,且isBegin0当前值为true的话,就要将isBegin0改为false
{
isBegin0 = false;
}
// 只有在isBegin0为false时才打印输出
if(!isBegin0)
{
printf("%c", number[i]);
}
}
printf("\t");
}
void Print1toMaxN(int n)
{
if (n <= 0) return;
// 用字符串表示大数
char *number = new char[n + 1];
if (number == nullptr) return; // 记住:分配内存后检查是否分配成功
memset(number, '0', n);
number[n] = '\0'; // 赋初值时别忘了结束标志,别粗心写成了\o
// 字符串代表的数字每次加1,然后打印输出
while (!IncreaseNumber(number))
{
PrintNumber(number);
}
}
int main()
{
int n;
cin >> n;
Print1toMaxN(n);
system("pause");
return 0;
}
思路二:
最大的n位数,即每一位都是0~9的排列,从最低位开始递归,让每个位上从0置为9,然后打印输出。
#include <iostream>
using namespace std;
void PrintNumber(const char *number)
{
bool isBegin0 = true;
int length = strlen(number);
for (int i = 0; i < length; ++i)
{
if (isBegin0 && number[i] != '0')
{
isBegin0 = false;
}
if (!isBegin0)
{
printf("%c", number[i]);
}
}
printf("\t");
}
void Print1ToMaxNRecursively(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';
Print1ToMaxNRecursively(number, length, index + 1);
}
}
void Print1ToMaxN(int n)
{
if (n <= 0) return;
char *number = new char[n + 1];
if (number == nullptr) return;
number[n] = '\0';
//int length = strlen(number);
for (int i = 0; i < 10; ++i)
{
number[0] = i + '0';
Print1ToMaxNRecursively(number, n, 0);
}
delete[] number; // 别忘了释放内存
}
int main()
{
int n;
cin >> n;
Print1ToMaxN(n);
system("pause");
return 0;
}
虽然递归的方式代码比较简洁,感觉还是有点不好理解,自己走走代码慢慢消化吧。