[leetcode]386. Lexicographical Numbers

Given an integer n, return 1 - n in lexicographical order.

For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9].

Please optimize your algorithm to use less time and space. The input size may be as large as 5,000,000.

按照字典排序法来重新输出1-n的整数,乍一看比较像字符串排序问题,要不要把数字转换为字符串并逐个排序呢?显然,对于这种大范围数字问题且排序问题,这是不划算的,开销太大。
自己动手写一写数字排列的要求会发现明显的规律,当允许继续往数字后面加0时,肯定先加0,不能加0后再开始最低位1到9增加,但增加到9之后就要回到高一位的讨论了。所以其实任意一个数字,在这个排序要求下,判断他的下一位应该是什么,即可看,能乘10就乘10,不能就让最低位在9以内增加。然后回到高一位继续。
基于这种朴素的思想,我们给出如下三种解法:

方法一:递归
vector<int> lexicalOrder(int n) {
     vector<int> res;
     helper(res, 1, n);
     return res;
}
void helper(vector<int>& res, int a, int n) {
    if (a <= n) {
        res.push_back(a);
        helper(res, a*10, n);
        if (a % 10 < 9) helper(res, ++a, n);
        else return;
    }
    else return;
}
方法二:栈,迭代

递归在内部也是使用了自己的栈来进行的,类似于二叉树遍历的问题,我们同样可以在这里自己用栈来迭代实现递归的效果,话说这个字典排序输出很像二叉树的先序遍历,大家自己体会。

vector<int> lexicalOrder(int n) {
     vector<int> res;
     stack<int> s;
     s.push(1);
     while (!s.empty()) {
         int cur = s.top();
         s.pop();
         res.push_back(cur);
         if (cur % 10 < 9 && cur + 1 <= n) s.push(cur + 1);
         if (cur * 10 <= n) s.push(cur * 10);
     }
     return res;
}
方法三:不使用额外空间解法

这里也可以很巧妙的利用十进制除法,在完成低位1到9的输出后直接除以10回到高一位,这种方法相比于前两种效率最高,但最难想到。

vector<int> lexicalOrder(int n) {
     vector<int> res(n, 0);
     int cur = 1;
     for (int i = 0; i < n; i++) {
         res[i] = cur;
         if (cur * 10 <= n) {
             cur = cur * 10;
         }
         else {
             if (cur >= n) cur = cur / 10;
             cur++;
             while (cur % 10 == 0) cur = cur / 10;
             //注意这里得是while不能只是if,因为199加1到200,我们需要回到2,while保证我们回到变化那一位
         }
     }
     return res;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值