Python技术迷

组里新来的 00后,试用期工资8k,住家里没房贷。 昨天项目上线,全组人都在,6点01分他准时背着包走了。。。

刚看到个贴子,说组里来个00后,新人试用期8k住家里,项目上线当天,活干完六点一到就背包走人,老同事一问,人家回一句“活干完不走留着过年?”楼主当场无语,心里有点酸。

Image

网友回复也挺有意思,有的骂这小孩不讲团队精神,有的说准点下班天经地义,凭什么被道德绑架。

我觉得这事吧,关键不是00后多嚣张,而是我们这代人太习惯“多干就是好员工”了。说白了,合同写几点下班,就有权几点走,前提是把份内事做好。羡慕人家潇洒,不如学学人家的边界感:该干的认真干,额外的事要么给钱要么给时间。

当然,年轻人也别被“整顿职场”冲昏头,真本事、真价值才是底气。

算法题:相隔为 1 的编辑距离

有次产品跟我说,想做个「弱密码提示」,比如用户把密码从 abc123 改成 abc124,这俩其实只差了一个字符,他就想提示一句「你这新密码和旧密码几乎一样」。当时我脑子里蹦出来的就是——这不就是典型的「相隔为 1 的编辑距离」嘛。

所谓编辑距离,你可以简单理解成: 把字符串 A 变成字符串 B,最少要做几次「单字符的操作」。

操作一般就三种:

  • 插入一个字符:ab → acb
  • 删除一个字符:acb → ab
  • 替换一个字符:abc → adc

题目里的「相隔为 1 的编辑距离」,意思是: 只允许做 一次 操作,就能把一个串变成另一个串。多一次少一次都不行。

举几个例子你感受下:

  • "abc" 和 "abx":改 c -> x,一次替换 ✅
  • "abc" 和 "abxc":插入 x,一次插入 ✅
  • "abc" 和 "ac":删掉 b,一次删除 ✅
  • "abc" 和 "abc":不用改,编辑距离是 0 ❌(我们要的是恰好 1)
  • "abc" 和 "axyd":至少 2 步 ❌

这种题蛮适合「按长度分类」来想:

  1. 两个字符串长度差大于 1 比如 abc 和 a、abc 和 abcde 这种, 不管你怎么插删改,一次肯定够不到,直接返回 False 就行。

  2. 长度刚好相等 这种场景下,只能通过「替换」来实现一次编辑。 那就一位一位对比,数一下有几个位置不同:

  • 如果不同的位置 刚好 1 个 → 编辑距离是 1 ✅
  • 如果是 0 个(完全一样)或者大于 1 个 → 不是 1 ❌
  • 长度相差正好 1 这个是重点,也是最容易写错的地方。 比如 abc 和 abxc、abc 和 bc、abc 和 abcd 这种。

    这里你可以这么想:

    还得注意一个小细节: 如果一路对比都没遇到不一样的字符,但长度差 1,比如:

    • abc 和 ab这种情况其实也是编辑距离 1——在短串尾部插入/删掉一个字符就行。
    • 你只能「跳过」长串的当前这个字符一次
    • 超过一次不对齐,就说明至少要 2 次编辑了
    • 一定是「长的那个串」做了一次插入/删除

    • 换个角度看:用两个指针,从头往后扫,如果遇到不一样的字符:

    Python 版本一:直接按长度分类写

    先写个清爽一点的版本,逻辑展开写清楚:

    defis_one_edit_distance(s: str, t: str) -> bool:
    # 保证 s 是较短的那个,省得分情况写两遍
    if len(s) > len(t):
            s, t = t, s

        len_s, len_t = len(s), len(t)

    # 长度差大于 1,肯定不是
    if len_t - len_s > 1:
    returnFalse

    # 情况一:长度相等,只能通过“替换”
    if len_s == len_t:
            diff_cnt = 0
    for ch1, ch2 in zip(s, t):
    if ch1 != ch2:
                    diff_cnt += 1
    if diff_cnt > 1:
    returnFalse
    # 必须刚好一个不同,0 个不同说明距离是 0
    return diff_cnt == 1

    # 情况二:长度相差 1,只能“插入/删除”
        i = j = 0# i 指向短串 s,j 指向长串 t
        found_diff = False

    while i < len_s and j < len_t:
    if s[i] == t[j]:
                i += 1
                j += 1
    else:
    # 第一次遇到不一样的字符,可以“跳过”长串当前字符
    if found_diff:
    # 已经跳过过一次了,再遇到不对齐就说明 > 1 次编辑
    returnFalse
                found_diff = True
                j += 1# 相当于在短串位置插入/删除了一个字符

    # 如果循环结束还没发现不一样的,那就是短串是长串的前缀,
    # 比如 s = "ab", t = "abc",这种情况编辑距离也是 1
    returnTrue

    这个函数做的事就是: 判断 s 和 t 的编辑距离是不是 恰好等于 1,是就返回 True,否则 False。

    时间复杂度是 O(n),空间 O(1),面试官一般也就要这个水平。

    Python 版本二:写一个简单的测试

    写完函数最好自己跑几组对比一下,不然很容易在边界条件栽跟头:

    deftest_is_one_edit_distance():
        cases = [
            ("abc", "abx", True),    # 替换一个
            ("abc", "abc", False),   # 距离 0
            ("ab",  "cab", True),    # 在前面插入
            ("ab",  "acb", True),    # 中间插入
            ("ab",  "a",   True),    # 删除一个
            ("",    "a",   True),    # 空串和单字符
            ("",    "",    False),   # 两个空串,距离 0
            ("abc", "axyd", False),  # 至少两次编辑
            ("abc", "abcd", True),   # 尾部插入
            ("abc", "abxyz", False), # 长度差>1
        ]

    for s, t, expected in cases:
            got = is_one_edit_distance(s, t)
            print(s, t, got, "OK"if got == expected else"FAIL")


    if __name__ == "__main__":
        test_is_one_edit_distance()

    你真跑一遍,大概率就能对这题的所有坑有感觉了:

    • 完全相等要排除
    • 长度差必须 ≤ 1
    • 相差 1 的时候要好好处理「光是尾巴不同」这种情况

    这些如果不写测试,很容易漏一个。

    顺便说一句实际用法

    像开头说的那种「新旧密码太像了」的需求,基本就是:

    ifnot is_one_edit_distance(old_pwd, new_pwd) and old_pwd != new_pwd:
    # 两次差别比较大,可以放行
        ...
    else:
    # 太像了,给个提示
        ...

    或者在拼音纠错、搜索联想、简单的拼写检查里,也经常会用到「编辑距离 = 1」这个判断, 完整的编辑距离用动态规划会复杂不少,这种「只关心等不等于 1」的场景,就用上面这个 O(n) 的小函数,够用还省事。

    行,差不多就这样,你可以先把这段代码抄过去跑一跑,看下是不是符合你心里对这道题的预期。

    -END-

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

    🔥虎哥私藏精品🔥

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