现在的HR不直接说35岁不要,但筛选逻辑变了。35岁+普通公司+薪资20k>几乎收不到面试邀请
刚看到个贴子,说现在HR不明说“35岁不要”,但筛选逻辑变了:35岁+大厂背景+要30k,简历容易过;35岁+普通公司+要20k,基本没面试。
网友回帖有说“企业只是看性价比”,也有人骂“普通人太难了”。我觉得,这事吧,确实现实,但也不是完全没解。
对公司来说,大厂背书=风险小、好交代;普通公司出来的,就得拿更硬的证明——你能帮公司省多少钱、挣多少钱,而不只是“干了多少年”。
从我的角度看,35+想换工作,一方面要早点做规划,别等被动失业再慌;另一方面,简历里少写“负责XX工作”,多写“把什么指标做到多少”。年龄歧视一时改不了,但让自己的价值更清楚,被看到的机会才会多一点。
算法题:电话号码的字母组合
昨天晚上十一点多,我在公司楼下买奶茶,结果被我们组那个准备面试的小李一把拦住,说东哥你等会儿,我那个「电话号码的字母组合」还没整明白,让我给他讲讲。唉,奶茶都快凉了,我就站树底下给他现打了个草稿。
先把题目说清楚哈。老旧键盘手机你们见过吧,数字 2–9 上面是几个字母,比如 2 对应 "abc",3 对应 "def" 那种。现在给你一个只包含 2~9 的字符串,比如 "23",要把按这个号码可能打出来的所有字母组合都列出来,"23" 就是 ["ad","ae","af","bd","be","bf","cd","ce","cf"] 这种感觉。
用 Python 写的话,第一步肯定是把数字到字母的映射先写死在一个字典里,不要纠结:
digit_map = {
"2": "abc",
"3": "def",
"4": "ghi",
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz"
}
小李一开始想的很暴力,说是不是可以一层一层嵌套 for 循环。比如两位数就两层 for,三位数三层 for。听上去也能写,但问题是,位数是变的啊,面试官给你一个 7 位数字,你难道写七层 for?这代码一眼就没法看,对吧。
这个题标准解法就是回溯(你可以理解成「穷举 + 撤销」)。我当时就跟小李说,你把这串数字想成一棵树,第一层选第一个数字对应的字母,第二层在前面选择的基础上再选第二个数字对应的字母……一直选到最后一位,走到树底的每一条路,就是一个组合。
用 Python 写出来其实不长,就这一段:
from typing import List
defletter_combinations(digits: str) -> List[str]:
ifnot digits: # 边界:空字符串直接返回空列表
return []
digit_map = {
"2": "abc", "3": "def",
"4": "ghi", "5": "jkl",
"6": "mno", "7": "pqrs",
"8": "tuv", "9": "wxyz"
}
res = []
path = [] # 当前已经选好的那些字母
defbacktrack(index: int):
# index 表示我们现在处理到 digits 的第几位了
if index == len(digits):
# 走到底了,把当前路径拼成字符串丢进结果
res.append("".join(path))
return
current_digit = digits[index]
for ch in digit_map[current_digit]:
# 选一个字母
path.append(ch)
# 递归到下一位
backtrack(index + 1)
# 撤销刚才的选择
path.pop()
backtrack(0)
return res
这个代码现场讲的话,你可以这么理解。我们维护一个 path,就像在纸上一步步写字母。index 表示现在要处理第几位数字了。
比如输入 "23"。一开始 index = 0,当前数字是 '2',它有 'a','b','c' 三个选项。假设先选 'a',path = ['a'],然后递归进入下一位,index = 1,这时候处理 '3',有 'd','e','f' 三个选项,于是分别得到 'ad','ae','af' 三条路,走到底就收入结果。然后函数返回的时候,path.pop() 把最后那个字母删掉,回到 ['a'] 再删成 [],再去试 'b' 开头的三条路,以此类推。
小李当时问我一句,说为啥非得 path.pop() 呢,不 pop 会怎样。我说你可以试试不 pop,path 会一直往里 append,最后长度会越来越长,根本对不上 index 这一层,整个组合就乱掉了。回溯的精髓其实就俩字:恢复。每一层递归做完要把现场还原,不然后面的分支就全被你前面那次选择污染了。
再讲一点小细节,免得你面试的时候被问懵。时间复杂度大概是啥水平?每一位数字平均有 3~4 个字母,假设就按 4 个算,长度是 n,那总共有 4^n 种组合,每个组合长度是 n,所以严格算是 O(4^n * n)。但是面试的时候你说「指数级,4 的 n 次方这个数量级」,基本就够用了。空间复杂度呢,主要是递归栈的高度 n,加上结果列表本来就必须存下来,这个就别太纠结。
他又问有没有不用递归的写法,因为有人不喜欢递归。我就顺手又给他写了个迭代版,大概是这样,用一个队列一点点往后扩:
defletter_combinations_iter(digits: str) -> List[str]:
ifnot digits:
return []
digit_map = {
"2": "abc", "3": "def",
"4": "ghi", "5": "jkl",
"6": "mno", "7": "pqrs",
"8": "tuv", "9": "wxyz"
}
res = [""] # 先放一个空前缀
for d in digits:
tmp = []
for prefix in res:
for ch in digit_map[d]:
tmp.append(prefix + ch)
res = tmp
return res
这个思路其实也挺生活化:一开始你只有一个空前缀 "",遇到第一位数字比如 "2",就把它展开成 "a","b","c" 三个前缀;再遇到第二位 "3",就把每个前缀再拼上 "d","e","f" 变成 9 个前缀,如此循环,走完所有数字以后,剩下的这些前缀就是所有结果。没有递归,就一层层 for,把组合「滚雪球」一样滚大。
现场讲的时候我还顺手提醒了小李两个容易翻车的地方,一个是 digits 可能是空串,要记得直接返回 [],不要返回 [""],这个在 LeetCode 上会被判错;另一个是不要写成那种死嵌套 for,不好维护,也不优雅,面试官一眼就知道你平时刷题刷得少。
讲完这些,他说差不多懂了,让我赶紧去拿奶茶,我低头一看奶茶已经变成常温的了,算了,将就喝吧。你要是现在也在备面,把这个题亲手敲一遍,自己在纸上画一下那棵「选择树」,基本就稳了,遇到同类型的回溯题,套路都差不多。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB