題目:輸入數字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;
}
雖然遞歸的方式代碼比較簡潔,感覺還是有點不好理解,自己走走代碼慢慢消化吧。