《剑指offer》面试题12 打印1到最大的n位数 Java版

书中方法:这道题的一个陷阱在于不能用int或者long去存储你要打印的数,然后用打印函数打印,因为这个数可能会很大。如果加1后超出了最大的n位数,就不打印了。用最高位是否进位判断是否结束,打印的时候注意不要打印出前面可能出现的0.

    public void print(int n){
        if(n<=0){
            return;
        }
        //必须要用字符数组防止大数
        char[] c = new char[n];
        for(int i=0; i<n; i++){
            c[i] = '0';
        }
        
        while(!increment(c)){
            digitsPrint(c);
            
        }
    }
    
    private boolean increment(char[] c){
        boolean overflow = false;
        //因为是加1,当作从小数进位了1.
        int carry = 1;
        //从个位开始计算
        for(int i=c.length-1; i>=0; i--){
            int sum = c[i] - '0' + carry;
            //如果进位了
            if(sum == 10){
                if(i == 0){
                    overflow = true;
                    break;
                }
                carry = 1;
                c[i] = '0';
            }else{//如果没进位
                c[i] = (char)('0' + sum);
                break;
            }
        }
        return overflow;
    }
    
    private void digitsPrint(char[] c){
        int index = 0;
        while(c[index] == '0'){
            index++;
        }
        for(int i=index; i<c.length; i++){
            System.out.print(c[i]);
        }
        System.out.println();
    }

我的方法:看到“所有”和“打印”这样的关键字,很容易想到用回溯的方法去做,因为实质是求出所有组合,上面的方法也是为了能遍历到所有组合。和求字符串的全排列以及组合不同(题目28),这里字符可以重复使用(又联想到了打印n位以内数字不重复整数...这里不展开,后面再说)。回想一下我们打印字符串的全排列时,因为每个字符只能使用一次,所以我们得想办法保证每个字符只被选取一次(利用额外的数组或者交换)。现在我们只需要简单地在每个位子上选取可能出现的值,然后递归下去就行了。外层是一个控制长度的循环,内层为每一位选取数字,每一位上都有‘0’-‘9’字符可以选择(第一位除外)。

    public void print2(int n){
        if(n <= 0)return;
        
        List<String> result = new ArrayList<String>();
        String line = "";
        
        //用n控制位数
        for(int i=1; i<=n; i++){
            find(result, line, 0, i);
        }
        
        for(String s : result){
            System.out.println(s);
        }
        
        
    }
    
    private void find(List<String> result, String line, int level, int border){
        //每一位添加完毕后保存
        if(level >= border){
            result.add(new String(line));
            return;
        }
                //用户保护原始的line,即保护现场(可百度这个关键词)
        String temp = new String(line);
        for(int i=0; i<=9; i++){
            //第一位不能为0
            if(level == 0 && i == 0){
                continue;
            }else{
                                //当前位添加
                line += i;
                                //继续添加下一位
                find(result, line, level+1, border);
                //让line恢复,进入下次for循环
                                line = temp;
            }
        }
    }

猜你喜欢

转载自www.cnblogs.com/czjk/p/11611395.html