一刷剑指offer(12)——打印1到最大的n位数

博客探讨了在处理大数问题时如何打印从1到最大n位数的方法。通过字符串模拟数字加法,当首位产生进位时表明达到最大值。另外,提出数字排列解法,将n位数看作全排列问题,遍历所有可能的数字组合。
摘要由CSDN通过智能技术生成
题目:
输入数字n,按顺序打印出从1到最大的n位十进制数。比如输入3,则打印出1、2、3....999

这个题目貌似很简单,最直接的方法就是先求出最大的n位数,然后用一个循环从1开始逐个打印。但是要注意的是,当输入的n很大的时候,会产生溢出,需要考虑大数问题。

怎么表示大数?字符串或者数组。

1、字符串模仿数字加法

因为数字最大是n位,因此字符串长度应为n+1位(结束符号'\0'),当实际数字不够n位时,在字符串前半部分补0。

要做两件事儿:在字符串表达的数字上模拟加法,打印数字。

如何明确到了最大的n位数呢?虽然调用strcmp很简单,但是事件复杂度为O(n)。

注意到只有对“9999....9”加1的时候,才会在第一个字符(下标为0)产生进位,而其他情况都不会在第一个字符产生进位。因此当我们发现在加1的时候第一个字符产生了进位,则已经是最大的n位数,时间复杂度为O(1)。

bool Increment(char* number)
{
    bool isOverflow=false;
    int nTakeOver=0;
    int nLength=strlen(number);
    for(int i=nLength-1;i>=0;i--)
    {
        //nSum为低位需要加上的数值,nTakeOver为进位标志
        int nSum=number[i]-'0'+nTakeOver;
        //一进循环第一件事儿,给nSum++(累加)
        if(i==nLength-1)
            nSum++;
        //如果nSum>=10,也就是要进位了,进循环
        if(nSum>=10)
        {
            //如果是最高位进位,说明已经到了最大的n位数
            if(i==0)
                isOverflow=true;
            //否则进行一般进位操作
            else
            {
                nSum-=10;
                nTakeOver=1;
                number[i]='0'+nSum;
            }
        }
        //如果没有进位,则进行一般低位+1操作,跳出循环,输出
        else
        {
            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++)
    {
        //只有在碰到第一个非0的字符之后才开始打印,补位0不打印
        if(isBeginning0 && number[i]!='\0')
            isBeginning0=false;
        if(!isBeginning0)
        {
            cout<<number[i];
        }
    }
    cout<<"    ";
}
      
void Print1ToMaxofNDigits(int n)
{
    if(n<=0)
        return;
    char* number=new char[n+1];
    //将number的前n个字节赋为‘0’
    memset(number,'0',n);
    number[n]='\0';    
    while(!Increment(number))
    {
        PrintNumber(number);
    }
    delete []number;
}              

2、数字排列解法

换一种思路考虑这个问题,如果我们在数字前面补0,那么就会发现n位所有十进制数其实就是n个从0到9的全排列!也就是说,把数字的每一位都从0到9排列一遍,就得到了所有的二进制数。

void PrintNumber(char* number)
{
    bool isBeginning0=true;
    int nLength=strlen(number);
    for(int i=0;i<nLength;i++)
    {
        if(isBeginning0 && number[i]!='0')
            isBeginning0=false;
        if(!isBeginning0)
        {
            cout<<number[i];
        }
    }
    cout<<“    ”;
}

void Print1ToMaxOfNDigitsRecursively(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';
        Print1ToMaxOfDigitsRecursively(number,length,index+1);
    }
}

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值