Python技术迷

躲过了两次裁员,终于成为腾讯员工了!!!

刚刷到这个,真有点职场玄学那味儿了。

喜马拉雅这波员工估计挺复杂的,本来前面躲了两轮裁员,心里可能天天悬着,结果一转头,公司被腾讯收了,审批也过了,直接从“会不会被优化”变成“我成腾讯员工了”。

最搞的是脉脉上那句调侃,躲过两次裁员,总算熬成腾讯人。你看,打工人有时候真不是靠规划,纯靠命硬。

Image

以前是担心工牌哪天刷不开,现在可能开始琢磨腾讯福利、职级、年包了。HR看完都得沉默,领导估计也不好意思再画饼了。

这事最离谱的地方就是,本来以为是在逃生,结果跑着跑着进大厂了。谁看了不说一句:这班上得,剧情比短剧还会反转。

算法题:找到数组的中间位置

数组里这个位置,我一般不会真把它当“中间”看。

比如这个数组:

[2, 3, -1, 8, 4]

位置 3 上是 8,它左边是:

2 + 3 + (-1) = 4

它右边是:

4

左右相等,所以位置 3 就是要找的位置。

注意,这题坑人的地方不在代码长,而在“中间”两个字。它不是长度的一半,也不是下标在正中央,而是找一个下标,让它左边所有数的和,等于右边所有数的和。

我见过不少人第一眼就写成这样:

defmiddle_index(nums):
for i in range(len(nums)):
        left = sum(nums[:i])
        right = sum(nums[i + 1:])
if left == right:
return i
return-1

这代码能跑,样例也过。

但我不太喜欢这种写法。不是因为它丑,是因为它每走一个位置都重新算一遍和。数组一长,sum(nums[:i]) 和 sum(nums[i+1:]) 就开始反复扫数据。

这题真正应该抓住的是一个关系。

假设数组总和是 total,当前下标是 i,左边和是 left,当前值是 nums[i]。

那右边和就不用重新算了:

right = total - left - nums[i]

只要判断:

left == total - left - nums[i]

就行。

代码我一般会这么写:

deffind_middle_index(nums):
    total = sum(nums)
    left_sum = 0

for idx, value in enumerate(nums):
        right_sum = total - left_sum - value

if left_sum == right_sum:
return idx

        left_sum += value

return-1

拿刚才那个数组跑一遍:

nums = [2, 3, -1, 8, 4]
print(find_middle_index(nums))

输出:

3

这里有个顺序别写反。

判断完当前下标以后,才能把当前值加到 left_sum 里。因为题目要求的是“当前位置左边”的和,不包含当前位置本身。

这地方如果手快写成这样:

left_sum += value

if left_sum == total - left_sum - value:
return idx

基本就偏了。看着只挪了一行,但语义已经变了,当前位置的值被算进左边去了。

再看两个边界。

第一个,答案在最左边:

print(find_middle_index([0, 5, -5]))

输出:

0

下标 0 左边没有元素,左边和按 0 算。右边是 5 + (-5),也是 0。

第二个,根本找不到:

print(find_middle_index([1, 2, 3]))

输出:

-1

整题复杂度也很干净。

数组先求一次总和,再从左到右扫一次,所以时间复杂度是 O(n)。除了几个变量,没有额外开数组,空间复杂度是 O(1)。

这题我更建议记判断式,不要背代码:

左边和 == 总和 - 左边和 - 当前值

只要这个式子没写错,代码基本不会跑偏。