【递归】【leetcode】顺次数

题目:

我们定义「顺次数」为:每一位上的数字都比前一位上的数字大 1 的整数。

请你返回由 [low, high] 范围内所有顺次数组成的 有序 列表(从小到大排序)。

示例 1:

输出:low = 100, high = 300
输出:[123,234]
示例 2:

输出:low = 1000, high = 13000
输出:[1234,2345,3456,4567,5678,6789,12345]

来源:

1291. 顺次数

解题思路1:递归

拿到此题,第一反应是递归,拿回溯的代码套一下。你可能会问:为什么不叫回溯?此题中递归函数中只有1种可能,例如当前数字是12,那么下一个数字必定是123,而不是124,所以不存在回溯的情况。

使用递归需要注意的地方:

  • 结果无序,需要排序后输出
  • 注意数字达到10时的处理
class Solution {
public:
    vector<int> result;
    vector<int> sequentialDigits(int low, int high) {
        for (int i = 1; i < 10; i++) {
            int path = i;
            back(path, i+1, low, high);
        }
        sort(result.begin(), result.end());
        return result;
    }
    void back(int path, int next, int low, int high) {
        if (path >= low) {
            result.push_back(path);
        }
        if (next == 10) return;
        path = path * 10 + next;
        if (path <= high) {
            back(path, next+1, low, high);
        }
    }
};

解题思路2:一种取巧的思路

事先定义所有的顺次数,遍历即可,代码简单不做解释。

class Solution {
public:
    vector<int> sequentialDigits(int low, int high) {
        vector<int> result;
        int nums[36] = {
            12,23,34,45,56,67,78,89,
            123,234,345,456,567,678,789,
            1234,2345,3456,4567,5678,6789,
            12345,23456,34567,45678,56789,
            123456,234567,345678,456789,
            1234567,2345678,3456789,
            12345678,23456789,
            123456789};
        for (int i = 0; i < 36; i++) {
            if (nums[i] >= low && nums[i] <= high) {
                result.push_back(nums[i]);
            }
        }
        return result;
    }
};

解题思路3:规律

根据思路2得出,nums从第一行开始,数字宽度依次是2,3,4,5,6,7,8,9。定义一个变量width,记录数字的宽度,可以从2开始,也可以从数字low的宽度开始。

在相同宽度下,滑动数字窗口,根据当前数字得出下一个数字,如何计算,下面举例说明:

  • 在width=3的情况下,当前数字如果是234,那么下一个数字是:(2345) % 1000 = 345。
  • 在width=5的情况下,当前数字如果是23456,那么下一个数字是:(234567) % 100000 = 34567。

定义一个变量mod记录上面的1000, 100000,每当width+1时,mod = mod*10。

如果当前数字>high,遍历结束。

class Solution {
public:
    vector<int> sequentialDigits(int low, int high) {
        vector<int> result;
        int width = 0; // 位数
        int t = low;
        long mod = 1;
        while (t > 0) {
            width++;
            t /= 10;
            mod *= 10;
        }
        
        while (width < 10) {
            bool end = false;
            long sum = 0; // width组成的数字
            int n = 1;
            for (; n < width; n++) sum = sum * 10 + n; // 前width-1组成的数字
            for (; n < 10; n++) {
                sum = (sum * 10 + n) % mod;
                if (sum > high) {
                    end = true;
                    break;
                }
                if (sum >= low) {
                    result.push_back(sum);
                }
            }
            if (end) break;
            width++;
            mod *= 10;
        }
        return result;
    }
};

总结:

本人更倾向于思路1和2,思路2不必说,思路1可以根据回溯的套路写,较容易实现。

思路3没有套路可循,需要反复调试才能通过,也许它的运行效率较高,但实现复杂、编写耗时,不推荐。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值