老公税后收入从月薪20K+,骤降到月薪6K。想问下男同胞们,我现在该怎么做能让他好受一些?
刚看到个贴子,说博主老公收入从月薪2w多掉到6k,她自己税后13k,还有个去发达国家的机会,还带着刚出生的宝宝,就问怎么做能让老公好受点。
我的看法是:先别急着选国家,先选立场——你们俩是一队的。
男人收入骤降,自尊肯定受冲击,这时候最怕听到的是比较:“你看我赚得都比你多。” 最需要的是一句:“这段时间先我多扛一会儿,我们一起想办法。” 多肯定他的价值,不只看工资,多聊未来规划,让他参与决策,而不是被你“安排出局”。
至于出国,别变成谁为谁牺牲,而是算一笔“全家总收益”的账:发展前景、育儿环境、感情成本,都摊开说清楚。
选什么都是冒险,但只要是两个人商量后一起扛的决定,就不会是谁欠谁。
算法题:Z 字形变换
昨天晚上十一点多,我在沙发上划水,手机刷到我们组小李在群里问一句: “哥,那个 Z 字形变换到底咋实现啊,用 Python 写,总感觉哪哪都绕。”
我一看这题名字挺吓人,其实真不难,就是有点抽象。咱今天就边唠嗑边把这个题捋顺了。
题目意思很简单:给你一个字符串 s,还有一个行数 numRows,让你把这个字符串按 “Z 字形” 写下来,然后再一行一行读出来。
举个官方那种经典例子(别嫌丑哈):
s = "PAYPALISHIRING", numRows = 3
排成 Z 字形长这样:
P A H N
A P L S I I G
Y I R
一行一行读: "PAHNAPLSIIGYIR"
所以本质上就是:模拟写字 → 再按行读,就完事了。 听起来还挺像小学抄写作业对吧。
脑子里先有个画面,不要一上来就敲代码
你可以想象有几行纸条:
有 numRows行你手里拿着一个笔,从上往下写,写到最底下一行了,就折回来往上写 写到最上面,又往下写
就这么上下上下地来回走,把字符串一个字符一个字符写下去。
比如 numRows = 4 的时候,你写出来会像这样:
s = "0123456789ABCDEF", numRows = 4
0 6 C
1 5 7 B D
2 4 8 A E
3 9 F
你会发现笔的“当前行号”其实就这样走:
0,1,2,3,2,1,0,1,2,3,2,1...
是不是有点像一个小人,在几行之间上下爬楼梯。
所以代码核心思路其实就俩变量
别管什么高深公式,最省心的写法就是这一套:
准备一个列表
rows,长度是numRows,每一项都是当前行的字符串。准备一个变量
cur_row表示“我现在写到第几行了”。准备一个变量
step,要么是1(往下走),要么是-1(往上走)。遍历字符串里的每个字符:
把它加到 rows[cur_row]这一行里如果到了最顶行(0)或者最底行(numRows-1),就把 step反向然后 cur_row += step
最后把所有行拼起来就行了。
有一个小坑别忘了: 如果 numRows == 1,根本不存在上下走,直接返回原字符串,否则会 bug。
直接上代码,你可以丢到 LeetCode 那题(Zigzag Conversion / Z 字形变换)里跑:
defconvert(s: str, numRows: int) -> str:
# 特殊情况:只有一行,根本没法“Z 字形”,原样返回
if numRows == 1or numRows >= len(s):
return s
# 每一行先用空字符串占位
rows = [""] * numRows
cur_row = 0# 当前在哪一行
step = 1# 1 表示往下走,-1 表示往上走
for ch in s:
# 把当前字符写到当前行
rows[cur_row] += ch
# 到顶或者到底,掉头
if cur_row == 0:
step = 1
elif cur_row == numRows - 1:
step = -1
# 往下一行(或者上一行)走
cur_row += step
# 最后按行拼接就是答案
return"".join(rows)
你可以自己拿个简单点的例子跑一跑,比如:
print(convert("LEETCODE", 3))
自己在纸上画一下三行 Z 形的样子,再跟打印结果对比,一般印象就牢了。
这题复杂度挺“朴素”的:
每个字符只遍历一遍 → 时间复杂度 O(n)rows里总共存的字符也是n个 → 空间复杂度O(n)
n 就是字符串长度。
在算法题里,这已经是挺完美的复杂度了,没啥可优化的,顶多就是换种写法,比如不用字符串累加、用列表再 join,性能会再好一点点:
defconvert_fast(s: str, numRows: int) -> str:
if numRows == 1or numRows >= len(s):
return s
rows = [[] for _ in range(numRows)]
cur_row = 0
step = 1
for ch in s:
rows[cur_row].append(ch)
if cur_row == 0:
step = 1
elif cur_row == numRows - 1:
step = -1
cur_row += step
# 把每行的字符列表拼成字符串,再整体拼起来
return"".join("".join(row) for row in rows)
Python 里字符串是不可变的,+= 会不停创建新对象,字符串一长差距就出来了,用列表再拼更稳。
有几个点,你在面试的时候顺嘴能说出来,面试官一般会点点头那种:
边界条件
numRows == 1:直接返回s,因为根本不会形成 Z 字形numRows >= len(s):每个字符最多一行一列,也是直接return s
思路不是“画 Z”,而是“按行收集”很多人一开始会想:“我是不是要开一个二维矩阵,先把 Z 字形画出来,然后再按行读?” 这样也能做,但空间浪费巨大,很多位置是空的。 最好的方式其实就是:只关心每一行最后会有哪些字符,不关心它们列坐标。
方向反转的写法上面我用了 if cur_row == 0: step = 1 ... 这种写法。 你也可以玩一点小技巧,直接:
if cur_row == 0or cur_row == numRows - 1:
step = -step
这样每次到边界就取反,代码会再短一点,看你自己习惯。
反正这题你只要脑子里有那个“人在楼梯上上下走”的画面,再记住“按行收集”,Python 那几行代码就很好背。
下次要是有同事半夜微信问你这题,你直接把这段代码甩过去,再配一句:“别慌,这题就是模拟走路。”就显得你老稳了。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB