题目:输入数字n,按顺序打印出从1到最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的999。

这道题目看着很简单,最简单的思想就是先求出最大的n位数,然后用一个循环从1开始逐个打印,代码很简单:

void Print1ToMaxOfNDigits_1(int n)
{
   int number=1;
   int i=0;
   while(i++<n)
   {
     number*=10;
   }
   for(i=i;i<number;i++)
   {
      printf("%d\t",i);
   }
}

初看之下似乎没什么问题,但如果仔细分析这个问题,当输入的n很大的时候,我们求最大的n位数是不是用整形(int)或者长整形(long long)都会溢出?在这里我们没有考虑大数问题。

思路:我们可以用字符串或者数组来表达大数。用字符串表示数字的时候,最直观的方法就是字符串里面每个字符都是’0’到’9’之间的某个字符,用来表示数字中的一位。因为数字最大是n位,因此我们需要一个长度为n+1的字符串(字符串中最后一个是结束符号’\0’),当实际数字不够n位时,在字符串的前半部分补0。首先我们把字符串中的每一个数字都初始化为’0’,然后每一次为字符串表示的数字加1,再打印出来。

即分为两步:1.在字符串表达的数字上模拟加法 2把字符串表达的数字打印出来

void Print1ToMaxOfNDigits(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;
}


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++;//数字+1
        }
        if(nSum>=10)//值>=10要进位*******************
        {
            if(i==0)//如果已经到了第一位,进位就溢出
            {
                isOverflow=true;
            }
            else{//如果没有到第一位,就向前进位
                nSum-=10;//该位变为0,进一位
                nTakeOver=1;//进位+1
                number[i]='0'+nSum;
            }
        }
        else{//值<10,结束,准备打印该值***************
           number[i]='0'+nSum;
           break;
        }  

    }
    return isOverflow;
}


void PrintNumber(char *number)
{
   bool isBeginning0=true;
   int nLength=strlen(number);
   for(int i=0;i<nLength;i++)
   {
      if(isBeginning0 && number[i]!='0')//只有碰到第一个非0字符之后才开始打印
      {
          isBeginning0==false;
      }
      if(!isBeginning0)
      {
          printf("%c",number[i]);
      }
   }
   printf("\t");
}

上述思路虽然很直观,但是由于模拟了整数的加法,代码看起来有些冗长。下面我们换一种思路来考虑这个问题。如果我们在数字前面补0的话,就会发现n位所有十进制数其实就是n个从0到9的全排列。全排列用递归很容易,数字的每一位都可能是0到9中的一个数,然后设置下一位

void Print1ToMaxOfNDigits(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';
     Print1ToMaxOfNDigitsRecursively(number,n,0);
   }
   delete[] number;
}


void Print1ToMaxOfNDigitsRecursively(char* number ,int length,int index)
{
   if(index==length-1)
   {
      PrintNumber(number);
      return;
   }
   for(int i=0;i<10;++i)
   {
      number[index+i]=i+'0';
      Print1ToMaxOfNDigitsRecursively(number,length,index+1);
   }
}

void PrintNumber(char* number)
{
   int nLength=strlen(number);
   bool isBeginning0=true;
   for(int i=0;i<nLength;++i)
   {
      if(isBeginning0 && number[i]!='0')
      {
          isBeginning0=false;
      }
      if(!isBeginning0)
      {
          printf("%c",number[i]);
      }
   }
}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐