LeetCode 剑指Offer 17 打印从1到最大的n位数

LeetCode 剑指Offer 17 打印从1到最大的n位数

题目

在这里插入图片描述

解题

解题参考:面试题17. 打印从 1 到最大的 n 位数(分治算法 / 全排列,清晰图解)
在这里插入图片描述
但是面试中一定要考虑大数越界的情况,不然面试官出这道题就显得很奇怪~

解题一:不考虑大数越界

战术性假装不知道要考虑大数问题来个解法先缓缓。

// javascript
var printNumbers = function(n) {
    const right_limit = Math.pow(10, n) - 1;
    const res = new Array(right_limit);
    for (let i = 0; i < right_limit; ++i) {
        res[i] = i + 1;
    }
    return res;
};

解题二:考虑大数越界

在这里插入图片描述
注意,最高位在 num 数组的 index 为 0 的位置。
在这里插入图片描述

输入:n = 1
输出:['0','1','2','3','4','5','6','7','8','9']

输入:n = 2
输出:['00','01','02',...,'10','11','12',...,'97','98','99']

输入:n = 3
输出:['000','001','002',...,'100','101','102',...,'997','998','999']

在这里插入图片描述

// javascript
var printNumbers = function(n) {
    const dfs = (index) => {
        // 终止条件:已固定完所有位
        if (index === n) {
            // 截取 num 并拼接
            // n = 3 时, ['0','0','9'] start 为 2 截取 ['9'] s = '9'
            // n = 3 时, ['0','9','9'] start 为 1 截取 ['9', '9'] s = '99'
            let s = num.slice(start).join('');
            // 因为打印数字从 1 开始,所以 ‘0’ 不用存入 res
            // 本解法时用大数的思想来解题,题目要求返回整数列表,所以把字符串转换成整数
            if (s !== '0') res.push(parseInt(s));
            // 比如 n = 3, s = ‘9’ 时, nineCnt = 1, start = 2, 满足条件
            // 下一次的 s = ‘10’, start 在这里变成 1
            if (n - start === nineCnt) start -= 1;
        } else {
            for (let i = 0; i < 10; ++i) { // 遍历 0 - 9
                if (i === 9) nineCnt += 1;
                num[index] = String(i);    // 固定第 index 位为 String(i)
                dfs(index + 1);            // 去固定第 index + 1 位
            }
            // 举例1: 当前 res 的最后一个数是 9,nineCnt = 1,下一次的数是 10,没有数字 9
            // 举例2: 当前 res 的最后一个数是 99,nineCnt = 2,下一次的数是 100,没有数字 9
            // dfs(1) 里 nineCnt 回溯成 1,回到 dfs(0) 中 nineCnt 变成 0
            nineCnt -= 1;
        }
    } 
    const num = new Array(n);
    const res = new Array();
    let start = n - 1;                     // n 位数的最低位 index 为 n - 1
    let nineCnt = 0;                       // 9 的个数初始化为 0
    dfs(0);                                // 从最高位开始全排列递归
    return res;
};

在这里插入图片描述
上面的解法使用 n = nineCnt + start (表示 num 中 [start, n - 1] 范围的每一个字符都是 ‘9’)的规律来更新 start 以删除高位的多余 ‘0’,其间要注意 nineCnt 的增加(+1)和回溯(-1)处理。傻瓜一点的方式就是写一个 removeLeadingZeros 函数来处理。

var printNumbers = function(n) {
    const dfs = (index) => {
        if (index === n) {                     // 终止条件:已固定完所有位
            let s = removeLeadingZeros(num);   // 把高位多余的 ‘0’ 去掉并拼接,把非 0 的数字推进 res
            if (s !== '0') res.push(parseInt(s));
        } else {
            for (let i = 0; i < 10; ++i) {     // 遍历 0 - 9
                num[index] = String(i);        // 固定第 index 位为 String(i)
                dfs(index + 1);                // 去固定第 index + 1 位
            }
        }
    } 
    const num = new Array(n);
    const res = new Array();
    dfs(0);                                    // 从最高位开始全排列递归
    return res;
};

const removeLeadingZeros = (num) => {
    const n = num.length;
    let i = 0;
    while (i < n - 1 && num[i] === '0') {     // 至少会有一位,所以 i < n - 1
        i++;
    }
    return num.slice(i).join('');
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值