找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4159

积分

0

好友

542

主题
发表于 16 小时前 | 查看: 7| 回复: 0

最近一个关于“48岁老程序员被大厂裁员”的帖子引发了广泛讨论。帖子里提到,主人公不仅社保交满了20年,还有一笔可观的存款,计划回县城生活。

社交媒体关于48岁程序员裁员的讨论截图

有人说这是“体面退场”,未来靠利息和退休金,日子可能比很多还在加班的人更舒心。但也有人感慨,技术人卷到最后,赢家模板似乎是“拥有选择不工作的底气”。

这件事之所以引发共鸣,背后是对职业生涯和财务安全的普遍焦虑。大厂的年龄门槛现实且残酷,但更现实的是,能否从容应对这种变化,往往取决于工作之外的积累。没有足够的储备,所谓的“退场”可能就是一场硬仗。

聊完职场话题,我们切换一下频道,来看一道与之风格迥异但值得玩味的算法题——自除数。这道题本身不难,但正因为它简单,才更能检验我们写代码时是否把边界和逻辑想清楚了。

自除数:题意与核心思路

题目要求很直接:找出给定区间 [left, right] 内的所有自除数。一个自除数需要满足两个条件:

  1. 该数包含的每一位数字都不能是 0
  2. 该数必须能被其包含的每一位数字整除

举个例子,128 就是一个自除数。我们来验证一下:128 % 1 == 0128 % 2 == 0128 % 8 == 0,全部通过。而 120 就不是,因为它包含数字 0,直接不符合第一条规则。

解这道题的关键在于如何处理一个整数的每一位。在动手前,先明确两个容易踩坑的地方:

  • 保护原始数据:我们需要遍历数字的每一位来判断整除性,但最后做取模运算 (num % digit) 时,必须用原始的 num。所以遍历时要用一个临时变量(比如 cur)来操作,避免把原数拆没了。
  • 遇零则退:只要发现某一位是 0,这个数就绝对不可能是自除数,应该立即返回 False,没有必要继续检查后面的位数。这是一种有效的“剪枝”。

Python 实现与逐行解析

基于以上思路,我们可以先写一个辅助函数来判断单个数字是否为自除数。

def is_self_dividing(num: int) -> bool:
    cur = num  # 用 cur 来遍历位数,保护原始的 num
    while cur > 0:
        digit = cur % 10  # 取出当前最低位
        if digit == 0 or num % digit != 0:  # 核心判断:遇零或不能整除
            return False
        cur //= 10  # 去掉已处理的最低位,继续检查下一位
    return True

这个函数的逻辑很清晰:

  1. cur = num:创建临时变量。
  2. while cur > 0:当还有位数可以处理时,继续循环。
  3. digit = cur % 10:通过取模运算得到当前个位数。
  4. if digit == 0 or num % digit != 0:进行关键判断。注意这里取模用的是原始 num,而不是 cur
  5. cur //= 10:通过整数除法去掉刚刚处理过的个位。
  6. 如果循环顺利结束,说明所有位数都通过了检查,返回 True

有了判断单个数的函数,主函数就非常简单了,只需要遍历给定区间,收集符合条件的数即可。

def self_dividing_numbers(left: int, right: int) -> list[int]:
    ans = []
    for num in range(left, right + 1):
        if is_self_dividing(num):
            ans.append(num)
    return ans

我们来测试一下,计算 122 之间的所有自除数:

print(self_dividing_numbers(1, 22))
# 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]

结果符合预期。你可以验证一下,比如 15 满足 15 % 1 == 015 % 5 == 022 满足 22 % 2 == 0

复杂度分析与写法讨论

时间复杂度:假设区间内有 n 个数,检查每个数需要遍历其 k 位数字(k 与数字的位数相关,通常很小)。因此,总的时间复杂度是 O(n * k)。对于这类题目给定的数据范围,这种效率完全足够。

空间复杂度:除了存储结果的列表,我们只使用了常数级别的额外空间,所以是 O(n)(用于输出结果),或 O(1)(如果不考虑输出占用的空间)。

有些人可能会想到先把数字转换成字符串,然后遍历每个字符。这种方法当然也可以,但相比之下,直接使用 % 10// 10 的数学方法更贴近“数字处理”的本质,路径更短,效率也通常更高,显得更像是在实现业务逻辑,而非单纯拼凑题解。

完整代码

把辅助函数和主函数放在一起,就是这道题的完整解法:

def is_self_dividing(num: int) -> bool:
    cur = num
    while cur > 0:
        digit = cur % 10
        if digit == 0 or num % digit != 0:
            return False
        cur //= 10
    return True

def self_dividing_numbers(left: int, right: int) -> list[int]:
    ans = []
    for num in range(left, right + 1):
        if is_self_dividing(num):
            ans.append(num)
    return ans

总结

像“自除数”这样的题目,难点不在于算法有多深奥,而在于能否稳妥地处理边界条件(比如数字0),以及是否遵循清晰的逻辑(比如保护原始数据)。在面试或日常编程中,把简单问题实现得稳健、易读,往往比追求奇技淫巧更重要。

从开头的职场故事到这里的算法细节,看似不相关的两件事,其实都指向同一个核心:无论是规划职业生涯,还是解决一个具体的编码问题,清晰的思路、对细节的把握以及提前筹划的能力,都是应对变化的关键。技术人除了钻研代码,或许也该偶尔跳出来,思考一下更长期的命题。在云栈社区,我们既讨论技术难题的解法,也分享关于职业成长的观察与思考。




上一篇:Python代码检查与格式化工具Ruff实战指南:提升开发效率与CI速度
下一篇:GTC 2026技术前瞻:Vera Rubin平台交付在即,盘点英伟达800VDC电源生态关键方案
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-24 22:49 , Processed in 0.508455 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表