面试题17:打印从1到最大的n位数

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

错误方法:

先求出最大的n位数,再用一个循环从1逐个打印。但是当n很大时,我们求最大的n位数用int或long long可能都会溢出。所以我们需要考虑的是大数问题

常规方法:

用字符串解决大数问题。本题中需要重点解决两大问题:1.字符串表示的大数模拟加法;2.把字符串表达的数打印出来。

字符串表示的大数模拟加法:

  1. 对于每一个字符串,计算加法都是从个位加1。从字符到int类型的计算方法:number[i] - '0';
  2. 用局部变量nSum表示每一个上的字符,都等于本位+进位。由nSum是否等于10判断是否需要进位,若是,进位标志nTakeOver=1,nSum所在位变为0。下一次迭代时,下一个位会加上进位。
  3. 如何判断结束:若最大的数999……99加1,则最高位会变为10,而其他情况都不会在第一个字符上产生进位,所以当加1时发现第一个字符产生了进位,表明已经到了最大的n位数了。
bool Increment(char* number)
{
    //是否越界标志
    bool isOverflow = false;
    //进位符
    int nTakeOver = 0;
    //number中字符的数量
    int nLength = strlen(number);
    for (int i = nLength - 1; i >= 0; i--)
    {
        //nSum表示每一位的计算方法:本位+进位
        int nSum = number[i] - '0' + nTakeOver;

        //每个number都是从个位加1,直至进位
        if (i == nLength - 1)
        {
            nSum += 1;
        }

        if (nSum == 10)
        {
            //若是最高位number[0]为10,表示已经到达最大值了,越界标志置为true
            if (i == 0)
                isOverflow = true;
            //若某位加1后为10,则进位1,本位变0;
            else
            {
                nSum -= 10;
                nTakeOver = 1;
                number[i] = '0';
            }
        }

        //若nSum结果在0-9之间,正常加1即可
        else
        {
            number[i] = '0' + nSum;
            break;
        }
    }
    return isOverflow;
}

把字符串表达的数打印出来

前面字符串加法操作时,当数字不够n位时,我们会在数字前面补0,打印的字符串应该删除前面这些0。所以在这个函数里,只有在碰到第一个非零的字符之后才会开始打印。

//删除前缀的0
void PrintNumber(char* number)
{
    //number中字符的数量
    int nLength = strlen(number);
    int zero_end = 0;
    while (number[zero_end]=='0'&&zero_end<nLength)
    {
        zero_end++;
    }
    for (int i = zero_end; i < nLength; i++)
    {
        cout << number[i];
    }
    cout << endl;
}

高级方法:

n位所有十进制数其实就是n个从0到9的全排列,用递归表达。递归结束的条件是我们已经设置好了数字的最后一位。

void Print1ToMaxOfDigits(int n)
{
    if (n < 0)
        return;
    char* number = new char[n + 1];
    memset(number, '0', n);
    number[n] = '\0';
    //从最高位为0-9,剩下的位递归排列
    for (int i = 0; i < 10; i++)
    {
        number[0] = i + '0';
        Print1ToMaxOfDigitsRecursively(number, n, 0);
    }
    delete[] number;
}

void Print1ToMaxOfDigitsRecursively(char* number, int length, int index)
{
    //若排列到了最后一位,打印字符串,退出函数。
    if (index == length - 1)
    {
        PrintNumber(number);
        return;
    }
    //递归排列
    for (int j = 0; j < 10; j++)
    {
        number[index + 1] = j + '0';
        Print1ToMaxOfDigitsRecursively(number, length, index + 1);
    }
}

迭代方法(全代码)

//打印大数,忽略前端的0
void printNumberWithoutZero(vector<int>& number)
{
    int len = number.size();
    //这里注意:迭代时第一个大数为全0,不用打印出来,直接返回空即可。若不处理,会出现数组越界错误
    vector<int> allZero(number.size(), 0);
    if (number == allZero)
        return;
    int j = 0;
    while (number[j]==0)
    {
        ++j;
    }
    for(int i=j;i<len;++i)
        cout << number[i];
    cout << endl;
}

//递归打印
void Print1ToMaxOfDigit(int n)
{
    if (n <= 0)
        return;
    vector<int> number(n, 0);
    for (int i = 0; i <= 9; ++i)
    {
        number[0] = i;
        PrintRecrusively(number,n, 1);
    }
}
void PrintRecrusively(vector<int>& number,int n,int index)
{
    //若数组下标已经打印到了第n位,因最高位为n-1位,所以可返回
    if (index == n)
    {
        printNumberWithoutZero(number);
        return;
    }        
    for (int i = 0; i <= 9; ++i)
    {
        number[index] = i;
        PrintRecrusively(number, n,index + 1);
    }
}
int main()
{
    int n = 3;
    Print1ToMaxOfDigit(n);    
    return 0;
}
全部评论

相关推荐

10-11 17:45
门头沟学院 Java
走吗:别怕 我以前也是这么认为 虽然一面就挂 但是颇有收获!
点赞 评论 收藏
分享
评论
1
1
分享
牛客网
牛客企业服务