更多题目请点链接:《剑指offer》目录索引
问题描述:
输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。
思路1:
(1)此题可归为大数处理问题:n可能很大,打印最大的n位数就存在溢出现象
(2)解决方法:采用高精度算法;使用一个数组arr来表示所要打印的数,将其以字符串的形式存储,并模拟数字加法
(3)加法进位:分析进位时,发现只有9、99、999、9999…….进行加1时,最高位才会发生进位故当加到这些数字时,需要发生进位
(4)最大的n位数:由上面所分析的进位问题,我们发现这些数字发生进位之后,数字就会比当前数字多一位,故这些数字(9、99、999….)为最大的n位数
(5)打印:由于我们将这些数字保存时,arr[0]为高位,如果不做处理,打印2位数时就会打印出这样一系列数:01 02 03 04………为了避免这样的情况,我们加一标记进行判断,从高位开始遍历,当遇到不是字符’0’的字符,即为要打印的数
代码:
void Print1ToMax(int n)
{
assert(n>0);
//将数字存放到数组当中
char* arr = (char*)malloc(sizeof(char)*(n + 1));
assert(arr);
memset(arr, '0', sizeof(char)*n);
arr[n] = '\0';
while(IncreamNumber(arr)==0)
{
//加法到最大数,开始打印
PrintNumber(arr);
}
free(arr);
arr = NULL;
}
int IncreamNumber(char* arr)
{
int i = 0, nbit = 0;
int len = strlen(arr);
for (i = len - 1; i >= 0; i--)
{
//将字符转化为数字
int sum = arr[i] - '0' + nbit;
//如果在最低位,进行加法
if (i == len - 1)
sum++;
if (sum >= 10)
{
if (i == 0)
{
//如果在最高位要进位,表示已经打印到最大数,返回1
return 1;
}
else
{
//如果没有在最高位,需要进位,则将进位变量置1
sum -= 10;
nbit = 1;
arr[i] ='0'+sum;
}
}
else
{
//如果不需要进位,直接存放到数组中
arr[i] = sum + '0';
break;
}
}
return 0;
}
void PrintNumber(char* arr)
{
int i = 0, flag = 1;
int len = strlen(arr);
for (i = 0; i < len; i++)
{
if (flag == 1 && arr[i] != '0')
{
//当遇到需要的数字时,flag置0
flag = 0;
}
if (flag==0)
{
printf("%c", arr[i]);
}
}
printf("\t");
}
思路2:
方法:采用递归排列方式来打印我们所需要的数;
思想:数学中只有0~9这10个数字,不管是1位数还是2位数还是3位数等等,都是这10个数字的排列而来;因此我们只需在相应的位数上排列这10个数字,在打印这些数字
相应位排列:先排列最高位,在排列次高位,直到最低位即可
代码:
void Print1ToMaxR(int n)
{
assert(n>0);
//将数字存放到数组当中
char* arr = (char*)malloc(sizeof(char)*(n + 1));
assert(arr);
memset(arr, '0', sizeof(char)*n);
arr[n] = '\0';
int i = 0;
for (i = 0; i < 10; i++)
{
//最高位排列
arr[0] = i + '0';
Print1ToMaxNumberR(arr, n, 0);
}
free(arr);
arr = NULL;
}
void Print1ToMaxNumberR(char* arr, int len, int index)
{
if (index == len - 1)
{
PrintNumber(arr);
return;
}
for (int i = 0; i < 10; ++i)
{
//在排列次高位到最低位的值
arr[index + 1] = i + '0';
Print1ToMaxNumberR(arr, len, index + 1);
}
}