Python技术迷

我同事当了别人小三,全公司都知道了 就她觉得自己藏得挺好。

这姐们儿是真把全公司当瞎子啊。

同事最近突然生活升级,之前中午还跟大家一起热饭盒,现在天天外卖起步,偶尔还去商场楼上吃。包换得勤,鞋也像刚从专柜拎出来的。问题是大家工资都差不多,五千多一个月,她这消费水平看着像项目奖金按天发。

Image

更离谱的是,楼下经常有个四十来岁的男人开车来接她,车挺扎眼。她一口咬定那是亲戚。可那人下车又是搭肩又是贴腰的,怎么看都不像普通亲戚。有人开玩笑问了一句,她还急了,说别人管太宽。

关键全公司其实早就看明白了,就她还觉得自己演得挺自然。茶水间都快传成连续剧了,她还在那儿装没事人。打工人最烦这种,工资没涨,瓜倒是越来越刺激。

算法题:山脉数组的峰顶索引

数组像这样:

[1, 3, 7, 12, 9, 4, 2]

峰顶下标是 3,因为 12 最大。

这题第一眼很容易写成这样:

defpeak_index(arr):
return arr.index(max(arr))

能过吗?大概率能过一部分。

但这写法我一般不太愿意交,原因很简单:它把“山脉数组”这个条件浪费掉了。题目已经告诉你,数组先严格递增,再严格递减。你还从头扫一遍找最大值,那就有点像数据库明明有索引,结果你非要全表扫。

山脉数组大概长这样:

下标:0  1  2  3  4  5
值:  2  5  9  7  3  1
          ^
        峰顶

站在任意一个位置 mid,只看它和右边那个数:

arr[mid] < arr[mid + 1]

说明还在往上爬,峰顶肯定在右边。

比如:

2, 5, 9, 7, 3
   ^
mid = 1
5 < 9

这时候左边不用看了,峰顶不会在 mid 以及 mid 左边。

反过来:

arr[mid] > arr[mid + 1]

说明已经开始下坡了,峰顶要么就是 mid,要么在 mid 左边。

这里别急着把 mid 扔掉,这个地方我见过不少人写错。

正确代码我会这么写:

defmountain_top_index(nums):
    left = 0
    right = len(nums) - 1

while left < right:
        mid = (left + right) // 2

if nums[mid] < nums[mid + 1]:
            left = mid + 1
else:
            right = mid

return left

这段代码短,但里面有个细节要盯一下:

right = mid

不是:

right = mid - 1

因为当 nums[mid] > nums[mid + 1] 时,mid 自己是有可能成为峰顶的。你把它减掉,可能直接把答案删了。

拿一组数据跑一下:

nums = [0, 2, 6, 10, 8, 5, 1]

print(mountain_top_index(nums))
print(nums[mountain_top_index(nums)])

输出:

3
10

再看边界一点的:

cases = [
    [0, 1, 0],
    [1, 4, 7, 3],
    [2, 6, 9, 11, 5],
]

for arr in cases:
    idx = mountain_top_index(arr)
    print(arr, "峰顶下标:", idx, "峰顶值:", arr[idx])

这种题不难,难的是别把它写成“找最大值”。

普通扫描是这样:

defscan_top_index(nums):
    best = 0

for i in range(1, len(nums)):
if nums[i] > nums[best]:
            best = i

return best

时间复杂度是 O(n)。

二分写法是 O(log n)。

数组长度小的时候,两者没什么差别。但算法题考的不是你能不能跑出来,而是你有没有吃到题目给的条件。

山脉数组这四个字,真正有用的地方就在这里: 一边上坡,一边下坡。 只要能判断当前位置处在上坡还是下坡,就能把一半数据直接扔掉。

最后再放一个完整版本:

classSolution:
defpeakIndexInMountainArray(self, arr):
        left = 0
        right = len(arr) - 1

while left < right:
            mid = (left + right) // 2

if arr[mid] < arr[mid + 1]:
                left = mid + 1
else:
                right = mid

return left

这题交这个就够了。

别加太多花活,越花越容易把 mid 那个位置搞丢。