Python技术迷

某老板娘:试用期结束了,你没通过考核,试用期没有工资!

刚刷到这个,真给我看乐了。

老板说试用期结束了,你没通过考核,所以试用期没有工资。啊?这话听着就像把公司当自己家游戏厅了,规则现编,输了员工买单。

试用期是试用,不是白干。人家天天打卡、干活、交付,你最后一句“不通过”就想把工资抹了,这不是考核,这是空手套打工人。 老板可能觉得自己挺聪明,省了一笔钱,实际上这话一说出口,HR估计都得沉默两秒。

Image

最搞笑的是,有些公司还真把“试用期”当免死金牌,想留就留,想踢就踢,钱也想赖。问题是员工不是来体验生活的,房租水电饭钱哪个不真要钱?

这种老板别考核员工了,先考核一下自己懂不懂当老板吧。

今日算法题

字符串反转这题,看着太短,反而容易写飘。

尤其是 Python,一上来写:

s = s[::-1]

本地一跑,结果是对的。提交到要求“原地修改”的题目里,可能直接不认。

这个地方我一般先看题目给的数据结构。如果传进来的是字符串,那字符串不可变,返回一个新字符串没问题;如果传进来的是字符数组,比如:

["h", "e", "l", "l", "o"]

那就别偷懒了,题目大概率要你在原数组上改。

最容易误判的是这种写法:

defreverse_string(chars):
    chars = chars[::-1]

这段代码看着像反转了,其实只是让局部变量 chars 指向了一个新列表。外面的那个列表,没动。

写个现场小测试就能看出来:

data = ["h", "e", "l", "l", "o"]

defbad_reverse(chars):
    chars = chars[::-1]

bad_reverse(data)
print(data)

输出还是:

['h', 'e', 'l', 'l', 'o']

这种 bug 不难,但很讨厌。因为你盯着函数里面看,觉得没问题;真正的问题在“引用没改到原对象”。

这题最稳的写法,就是双指针。

defreverse_string(chars):
    left = 0
    right = len(chars) - 1

while left < right:
        chars[left], chars[right] = chars[right], chars[left]
        left += 1
        right -= 1

没花活。

左边一个指针,右边一个指针,每次交换两个字符,然后往中间收。直到两个指针撞上,或者交错,反转就结束了。

拿 "hello" 走一遍:

["h", "e", "l", "l", "o"]

第一轮交换 h 和 o:

["o", "e", "l", "l", "h"]

第二轮交换 e 和 l:

["o", "l", "l", "e", "h"]

中间那个 l 不用管,它自己就在正确位置上。

如果是偶数长度,比如:

["c", "o", "d", "e"]

流程也一样:

data = ["c", "o", "d", "e"]
reverse_string(data)
print(data)

输出:

['e', 'd', 'o', 'c']

这题有个小细节:循环条件要写 left < right,别写复杂了。写成 left <= right 也能跑,但中间那个字符会跟自己交换一次,没有意义。算法题里这种多余动作不一定扣分,但我不太喜欢,说明边界没想清楚。

时间复杂度是 O(n),因为每个字符最多参与一次交换。

空间复杂度是 O(1),因为没有重新开一个列表,只用了两个指针变量。

如果题目不是要求原地修改,而是让你返回一个新字符串,那 Python 可以这么写:

defreverse_text(text):
    buf = list(text)

    left, right = 0, len(buf) - 1
while left < right:
        buf[left], buf[right] = buf[right], buf[left]
        left += 1
        right -= 1

return"".join(buf)

为什么不直接用 text[::-1]?

面试或者刷题时可以用,但你要知道它背后会创建新对象。题目考“反转字符串”,多数时候不是考你会不会切片,而是看你能不能把原地修改、边界、复杂度这几个点讲清楚。

这题真正该记住的不是代码,而是判断顺序:

先看输入是字符串还是字符数组。

再看题目要返回新值,还是原地修改。

最后再决定能不能用切片。

顺序错了,代码越短,坑越隐蔽。