Python技术迷

技术总监拿了45万年终突然离职,我们以为是被别人挖走了,结果是总监发现自己管理的两个核心项目,被公司偷偷转移给新空降的领导~

刚看到个贴子,说一技术总监拿了45万年终奖转头就提离职,本来同事都以为是被大厂高薪挖走,结果内幕是:他辛苦几年打下来的两个核心项目,被公司悄悄转给了新空降的领导。

Image

网友回帖有说“拿了钱就别矫情的”,也有替总监抱不平的,觉得这是赤裸裸架空。

我觉得这事吧,核心不是钱,而是“被消失的控制权”。项目被拿走,就像房本上把你名字擦掉,再厚的年终奖也只是分手费。对公司来说,这是短期算计,把人当一次性工具;对个人来说,就是个信号:这里已经不值得继续押注。

算法题:缺失的区间

你有一段连续的整数区间 [lower, upper], 然后手里又有一个已经排好序、互不重复的数组 nums,里面的数字都在这段区间里。

但是呢,这个数组不一定把区间里的所有数字都覆盖了,中间可能断断续续少一截一截的。 题目的意思就是:把这些“缺失的连续区间”找出来。

举个很具体的例子:

lower = 0
upper = 9
nums = [0, 1, 3, 7, 8]

那整段区间是 0,1,2,3,4,5,6,7,8,9, 你手里的只有 0,1,3,7,8,所以少了:

  • 2
  • 4,5,6
  • 9

常见的输出格式会长这样:

["2", "4->6", "9"]

单个数字直接写数字,多于一个数字就写成 start->end 这种形式。

题目就这个意思,没别的花活。

我一般会先在脑子里画个数轴,大概是这样:

lower ... 若干数字 ... upper

我们要找的,其实就是:“数组中的相邻数字”之间差出来的那一段。

但这里有两个“隐形邻居”很关键:

  • lower 的前一个数:lower - 1
  • upper 的后一个数:upper + 1

为什么要整这俩?

因为你得把“开头缺一段”和“结尾缺一段”也统一成“中间缺一段”的写法,不然逻辑会变得很乱。

所以完整的套路是:

  1. 设一个变量 prev = lower - 1,表示“上一个出现的数字”

  2. 把数组 nums 后面强行拼一个upper + 1,当成“终点哨兵”

  3. 然后从左到右遍历 nums + [upper + 1],记当前数字为 cur

  4. 每次看 cur - prev 的差:

  • 起点就是 prev + 1
  • 终点就是 cur - 1
  • 如果起点==终点,缺的是一个数
  • 不相等就是一段区间
  • 如果差小于 2,说明中间没少数字,直接往后走

  • 如果差大于等于 2,说明中间至少缺了一个数

  • 每轮结束记得 prev = cur

  • 核心其实就一句话:

    所有的“缺口”都存在于“两个相邻已知数字之间”。

    from typing import List

    deffind_missing_ranges(nums: List[int], lower: int, upper: int) -> List[str]:
        res = []

    # 1. 上一个看过的数字,从 lower - 1 开始,方便统一处理
        prev = lower - 1

    # 2. 在末尾拼一个 upper + 1,当成终点哨兵
    #    这样结尾缺的那段也能在循环里一次性处理掉
    for cur in nums + [upper + 1]:
    # 如果中间至少差了 2,说明有东西缺了
    if cur - prev >= 2:
                start = prev + 1
                end = cur - 1
    if start == end:
    # 只缺一个数
                    res.append(str(start))
    else:
    # 缺一整段
                    res.append(f"{start}->{end}")
    # 别忘了更新 prev
            prev = cur

    return res

    这个函数就是标准解了,丢到 LeetCode 那种地方也能跑。

    我们用几个例子捋一捋

    1)数组是空的

    print(find_missing_ranges([], 1, 5))  # ['1->5']

    解释:啥都没有,那整个 [1,5] 都是缺的。

    2)中间有洞

    print(find_missing_ranges([1, 3, 7], 0, 9))
    # ['0', '2', '4->6', '8->9']
    • prev = -1,cur = 1 → 缺 0
    • prev = 1,cur = 3 → 缺 2
    • prev = 3,cur = 7 → 缺 4->6
    • prev = 7,cur = 10(哨兵) → 缺 8->9

    你会发现头尾完全是被“当成中间情况”处理掉的,这就是那个 lower - 1 和 upper + 1 的意义。

    3)完全不缺

    print(find_missing_ranges([1, 2, 3], 1, 3))  # []

    每次 cur - prev 都小于 2,自然啥都不加。

    复杂度顺手算一下

    其实也简单:

    • 只遍历了一遍 nums,额外就一个哨兵,所以时间复杂度是 O(n)
    • 存结果的数组,最极端也就是 “数字/区间互相交替”,数量也是 O(n),所以空间复杂度也是 O(n)

    对面试官说的时候,别说得太花,就一句:“单次线性扫描,时间 O(n),额外空间 O(n) 存答案。” 就够了。

    几个特别容易写挂的地方我再捋一遍:

    • nums 可能是空的,要特判或者让算法自己兜住(上面这版是能兜住的)

    • 可能 nums[0] 比 lower 大,别漏了开头那段

    • 可能 nums[-1] 比 upper 小,别漏了结尾那段

    • 输出格式一定要区分:

      • 一个数:"2"
      • 多个数:"2->5"

    搞定这些,其实这题就属于那种:只要你敢写完,调两下就能 AC 的题。

    行,我就说到这儿,你可以自己把代码粘进本地跑几组数据试试,有啥想扩展的版本(比如允许重复、没排好序那种),也可以再一起改一版“加强版”的。

    -END-

    我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

    🔥虎哥私藏精品🔥

    虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB