面一个90年的经理岗,开口要40k+,本来聊得挺顺的。HR总监突然灵魂发问:你这年纪主动离职够有勇气啊。候选人苦笑:公司6个月没发工资了
刚看到个贴子,说有个90年的去面经理岗,开口40k+,前面聊得挺好,结果HR总监来一句:“这年纪主动离职挺有勇气。”候选人苦笑,说原公司已经6个月没发工资了,不走难道喝西北风。
网友们的回复我看了看,有人吐槽候选人要价高不自量力,也有人骂HR站着说话不腰疼,拖欠工资还谈忠诚。怎么说呢,我觉得这事首先得分清:半年没工资,离职不是“勇气”,是基本求生反应;其次,40k贵不贵,看的是能力、岗位价值和行业行情,跟年龄、听不听话真没多大关系。真正离谱的,是那个拖薪还想着员工死心塌地的公司。
从我的角度看,职场别老拿“稳定、忠诚”PUA人。公司可以算成本,打工人也有权算现金流。
力
算法题:区间子数组个数
有个整数数组 nums,再给你两个整数 left 和 right。 要数一数:有多少个连续子数组,它们里面的最大值刚好落在 [left, right] 这个区间里。
举个很经典的例子:
nums = [2, 1, 4, 3]
left, right = 2, 3
符合要求的子数组有三个:
[2]最大值 2 在区间里[2, 1]最大值还是 2[3]最大值 3 在区间里
所以答案是 3。
听起来挺简单,对吧?但直接暴力搞,其实挺容易超时。
最直接的思路:
枚举所有子数组(双层循环,左边界 i,右边界 j) 每次顺便算一下这段里最大的值 看这个最大值在不在 [left, right],在就计数 +1
伪代码大概这样:
ans = 0
for i in range(n):
cur_max = nums[i]
for j in range(i, n):
cur_max = max(cur_max, nums[j])
if left <= cur_max <= right:
ans += 1
问题也很明显: 数组长度如果是 1e5 级别,这就是 O(n²),直接寄。
那怎么把它变成 O(n) 呢?这题其实有个非常巧的小套路。
关键观察:先数“最大值 ≤ 某个值”的子数组
我们先别死盯着 [left, right],把问题拆一下。
定义一个函数 count_leq(bound): 统计最大值 ≤ bound 的子数组个数。
然后你会发现一个很妙的式子:
最大值在
[left, right]的个数 = 最大值 ≤right的个数 − 最大值 ≤left - 1的个数
为啥对?
“最大值 ≤ right” 里面,既包括最大值在 [left, right]的,也包括最大值 < left 的“最大值 ≤ left - 1” 只包括最大值 < left 的 一减,就把“太小的那些”减掉了,剩下的就是我们要的那一批
所以整个题目就变成了:如何 O(n) 算出 count_leq(bound)?
单次扫描搞定 count_leq(bound)
这个函数的思路其实很朴素:
从左往右扫一遍数组,维护一个变量 cur —— 表示以当前下标结尾、且最大值 ≤ bound 的连续子数组有多少个。
规则只有两条:
当前元素
x如果x <= bound:
那它可以和前面那些“合法子数组”接上 也可以单独成一个新的子数组 所以 cur += 1
当前元素 x 如果 x > bound:
那所有包含它的子数组最大值都 > bound,不合法 以它结尾的合法子数组数量变成 0 所以 cur = 0
每走一步,把 cur 累加进 ans 就行了,因为:
对于每个位置 i, “以 i 结尾的合法子数组个数”就是 “以 i 结尾刚刚新增的那批子数组数量”。
代码长这样:
defcount_leq(nums, bound):
ans = 0
cur = 0
for x in nums:
if x <= bound:
cur += 1# 新增的合法子数组,都以当前 x 结尾
else:
cur = 0# 被一个大于 bound 的数打断
ans += cur
return ans
整个过程只扫一遍数组,所以是 O(n),而且只用常数空间。
上面都串起来,就是完整答案了,用 Python 写得干净一点:
from typing import List
defcount_leq(nums: List[int], bound: int) -> int:
"""
统计 nums 中,最大值 <= bound 的连续子数组个数
"""
ans = 0
cur = 0
for x in nums:
if x <= bound:
cur += 1
else:
cur = 0
ans += cur
return ans
defnum_subarray_bounded_max(nums: List[int], left: int, right: int) -> int:
"""
返回最大值在 [left, right] 区间内的子数组个数
"""
# 最大值 <= right 的子数组数目
total_leq_right = count_leq(nums, right)
# 最大值 <= left - 1 的子数组数目(也就是最大值 < left)
total_lt_left = count_leq(nums, left - 1)
# 两者相减,剩下的就是最大值在 [left, right] 的
return total_leq_right - total_lt_left
if __name__ == "__main__":
nums = [2, 1, 4, 3]
left, right = 2, 3
print(num_subarray_bounded_max(nums, left, right)) # 输出 3
复杂度简单算一下:
count_leq是 O(n),调用两次还是 O(n), 空间 O(1)。
就这样,这题思路其实就两步: 先学会数“最大值 ≤ 某个值”的子数组,再用一个减法把区间卡出来。 你可以自己随便再写几个测试用例试试,比如数组里全都小于 left、或者全都大于 right,看结果是不是合理。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB