找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5456

积分

0

好友

721

主题
发表于 1 小时前 | 查看: 4| 回复: 0

刚刷到这个帖子,我第一反应就是,这哥们不是没弱点了,是把命门藏得太深了。月供才0.44元,什么概念,基本等于房贷系统象征性跟你打个招呼,连杯矿泉水都买不了。像这样的职场吐槽,在云栈社区开发者广场里也司空见惯。

你让领导怎么拿捏,画饼?人家不缺这口。加压?大不了准点下班。谈忠诚?他估计心里只会哦一声。

职场里大多数人难受,说白了还是背着点东西,房贷车贷娃的学费,哪样都能被精准戳中。你没有这些包袱,整个人气质都不一样,开会被点名都像在听别人家的事。

领导最怕的就是这种,骂两句没反应,谈前途也没波澜,想靠“你再忍忍”那套往前推,结果人家根本不接。

这种状态看着离谱,其实很现实。手上没链子,谁也别想随便拽着你跑。

算法题:滑动窗口中位数

堆一排数字进窗口里,最烦的不是求最大值,那个单调队列一把梭就完了。中位数不一样,这玩意儿卡人的地方在于:窗口会滑,左边出去一个,右边进来一个,你不仅要知道当前“中间那个数”是谁,还得把已经滑出去的旧值及时清掉。这里我第一眼就不太信“每次排序一次”这种写法,能过小数据,窗口一大基本就开始喘了。写题的时候,先把“插入”和“删除”这两个动作稳住,再谈中位数。

这题比较顺手的做法,是搞两个:一个大根堆放左半边,保存较小的一半;一个小根堆放右半边,保存较大的一半。这样一来:

  • 奇数个元素时,中位数就是左堆堆顶;
  • 偶数个元素时,中位数是左右堆顶的平均值。

麻烦在删除。Python 的堆不支持删除任意元素,真去线性删除就慢了。我一般不这么干,直接“延迟删除”:先记账,等这个元素冒到堆顶时再顺手弹掉。

代码别写太花,关键是几个动作分清楚:加元素、删元素、平衡两个堆、取中位数。

import heapq
from collections import defaultdict
from typing import List

class MedianWindow:
    def __init__(self):
        self.small = []  # 大根堆,存负数
        self.large = []  # 小根堆
        self.delayed = defaultdict(int)
        self.small_size = 0
        self.large_size = 0

    def prune(self, heap):
        while heap:
            num = -heap[0] if heap is self.small else heap[0]
            if self.delayed[num] == 0:
                break
            self.delayed[num] -= 1
            if self.delayed[num] == 0:
                del self.delayed[num]
            heapq.heappop(heap)

    def balance(self):
        if self.small_size > self.large_size + 1:
            heapq.heappush(self.large, -heapq.heappop(self.small))
            self.small_size -= 1
            self.large_size += 1
            self.prune(self.small)
        elif self.small_size < self.large_size:
            heapq.heappush(self.small, -heapq.heappop(self.large))
            self.small_size += 1
            self.large_size -= 1
            self.prune(self.large)

    def add(self, num: int):
        if not self.small or num <= -self.small[0]:
            heapq.heappush(self.small, -num)
            self.small_size += 1
        else:
            heapq.heappush(self.large, num)
            self.large_size += 1
        self.balance()

    def remove(self, num: int):
        self.delayed[num] += 1
        if num <= -self.small[0]:
            self.small_size -= 1
            if num == -self.small[0]:
                self.prune(self.small)
        else:
            self.large_size -= 1
            if self.large and num == self.large[0]:
                self.prune(self.large)
        self.balance()

    def median(self, k: int) -> float:
        if k % 2 == 1:
            return float(-self.small[0])
        return (-self.small[0] + self.large[0]) / 2.0

def medianSlidingWindow(nums: List[int], k: int) -> List[float]:
    mw = MedianWindow()
    ans = []

    for i, x in enumerate(nums):
        mw.add(x)
        if i >= k:
            mw.remove(nums[i - k])
        if i >= k - 1:
            ans.append(mw.median(k))

    return ans

比如 nums = [1,3,-1,-3,5,3,6,7], k = 3,窗口从左往右滑,中位数依次是 [1,-1,-1,3,5,6]。这个过程里,堆里可能暂时还躺着已经出窗口的旧值,但只要它没跑到堆顶,就先记着;一旦顶上撞见了,再清。这样复杂度能压到 O(n log k),这才像样。

这题真正容易写错的,不是取中位数,而是平衡堆大小的时候把“有效元素个数”和“堆里实际元素个数”混了。只要这两个概念分不开,结果就会一会儿对一会儿错,测到重复值更多的时候尤其明显。写完别急着交,拿 [1,1,1,1][1,2,2,3] 这种带重复值的用例先过一遍,很多 bug 当场就露出来了。




上一篇:机器人落地为何困难重重?从180亿融资到全栈整合的产业真相
下一篇:IT经理的离职面谈实战:如何问、听、做,把告别变成组织诊断
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-5-19 01:51 , Processed in 0.646047 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表