题目:
输入数字n,按顺序输出从1最大的n位10进制数。比如输入
3,则输出
1、
2、
3一直到最大的
3位数即
999。
分析:这是一道很有意思的题目。看起来很简单,其实里面却有不少的玄机。应聘者在解决这个问题的时候,最容易想到的方法是先求出最大的n位数是什么,然后用一个循环从1开始逐个输出。很快,我们就能写出如下代码:
// Print numbers from 1 to the maximum number with n digits, in order void Print1ToMaxOfNDigits_1(int n) { // calculate 10^n int number = 1; int i = 0; while(i++ < n) number *= 10; // print from 1 to (10^n - 1) for(i = 1; i < number; ++i) printf("%d\t", i); }
初看之下,好像没有问题。但如果我们仔细分析这个问题,就能注意到这里没有规定n的范围,当我们求最大的n位数的时候,是不是有可能用整型甚至长整型都会溢出?分析到这里,我们很自然的就想到我们需要表达一个大数,最常用的也是最容易实现的表达大数的方法是用字符串或者整型数组(当然不一定是最有效的)。
采用类似“n位k进制枚举”的算法(也类似于《编程之美》“电话号码对应英文单词”),代码如下:
const unsigned MaxBit = 10; static unsigned outArr[MaxBit]; const char *HighBit = "123456789"; const unsigned HighNum = 10; const char *OtherBit = "0123456789"; const unsigned OtherNum = 11; void PrintAllNumberWithNBits(unsigned int N) { //输出位数为N位的数,即:10^(N-1)...10^N-1 if (N < 1) return; for (unsigned i = MaxBit-N; i < MaxBit; i++) if (i == MaxBit-1) outArr[i] = 0; else outArr[i] = 1; while (1) { int k = N; outArr[MaxBit-1-(N-k)]++; if(k==1 && outArr[MaxBit-1-(N-k)]>=HighNum) return; //前一个数字所有位均为9,循环结束 else if (outArr[MaxBit-1-(N-k)] >= OtherNum) { int j = k; while (j>1 && outArr[MaxBit-1-(N-j)]>=OtherNum) { outArr[MaxBit-1-(N-j)] = 1; j--; outArr[MaxBit-1-(N-j)]++; } if (j==1 && outArr[MaxBit-1-(N-j)]>=HighNum) return; } for (unsigned int i = MaxBit-N; i < MaxBit; i++) { if (i == MaxBit-N) cout << HighBit[outArr[i]-1]; else cout << OtherBit[outArr[i]-1]; } cout << endl; } } int main() { unsigned number = 0; cin >> number; for (unsigned i = 0; i < MaxBit; i++) outArr[i] = 0; // 依次输出位数为1,2,3...n-1位的数 for (unsigned i = 1; i <= number; i++) PrintAllNumberWithNBits(i); return 0; }
- public class Print_1_To_NDigit {
- /**
- * Q65.输入数字n,按顺序输出从1最大的n位10进制数。比如输入3,则输出1、2、3一直到最大的3位数即999
- * 1.使用字符串存放数字。int a=123 --> char[] a={'1','2','3'};
- * 2.递归。设置好第n位(最高位,对应char数组的第0个元素)后,接下来设置第n-1,n-2.....位
- * 3.打印时候,前面的0不输出,见printNumber(char[] number)
- */
- public static void main(String[] args) {
- int n=3;
- Print_1_To_NDigit p=new Print_1_To_NDigit ();
- p.print(n);
- }
- public void print(int n){
- char[] result=new char[n];
- printHelpRecursive(result,n,0);
- }
- //from result[0] to result[n-1],set 0-9 into it
- public void printHelpRecursive(char[] result,int length,int index){
- if(index==length){
- printNumber(result);
- }else{
- for(int i=0;i<=9;i++){
- result[index]=(char)('0'+i);
- printHelpRecursive(result,length,index+1);
- }
- }
- }
- //don't print the prefix '0'.e.g,when "0012",print "12"
- public void printNumber(char[] re){
- int len=re.length;
- boolean canPrint=false;
- for(int i=0;i<len-1;i++){
- if(!canPrint&&re[i]!='0'){
- canPrint=true;
- }
- if(canPrint){
- System.out.print(re[i]);
- }
- }
- System.out.println(re[len-1]);//the last bit is always printed.
- }
- }