程序员老鬼

面试了一个45岁的程序员,他要月薪2万,我同意了;结果面试完把他送到电梯口,他说如果是14薪的话,月薪1.8万也行。

刚看到个贴子,说有网友面试了个45岁的程序员,对方开口要2万,HR也答应了。结果送到电梯口,这位大哥又补一句:要是14薪的话,1.8万也行。

Image

我觉得这事吧,关键不在“2万还是1.8万”,而在这位程序员到底认不认可自己的价值。45岁还能出来找开发岗,本身就是能力和经验的证明,如果一开始报的价是认真算过的,那就别轻易往下掉;如果只是随口要个高价,电梯口再改,那确实显得不够成熟。

职场谈薪可以灵活,但底线要提前想清楚。钱是谈出来的,自信也是。

面试题:仓库经理

想象一下,你是仓库经理。 每天早上九点刚到仓库,保安老李一边喝豆浆一边跟你说:今天又是忙的一天啊。

系统里有一串操作记录,大概是这样的:

  • 正数:代表入库,比如 +100 是来了 100 箱货
  • 负数:代表出库,比如 -30 是拣了 30 箱发货

问题来了:你一开始仓库里要准备多少货,才能保证一天操作下来,中间任何时刻库存都不变成负数? 注意哦,中间一刻也不能为负,不然一堆订单就得 “缺货待补”。

这就是这个算法题的核心。

题目长啥样(抽象一丢丢)

给你一个 int 数组 ops,长度是 n。

  • ops[i] > 0 表示第 i 步有这多货进来
  • ops[i] < 0 表示第 i 步要发这么多货出去

问: 初始库存 startStock 至少要多少, 才能保证对这串操作做完的过程中,任意时刻库存都 >= 0。

当然啦,你不能改操作顺序,只能调高一开始仓库有多少货。

怎么想这事儿比较顺?

你可以脑补自己拿个小本子这样算:

  • 假设一开始是 0 箱
  • 每来一条操作,就把当前库存加上这个数
  • 一边算,一边盯着:哪个时刻库存最惨,最小是多少

比如操作是:[-5, +3, -2]

你从 0 开始算一遍:

  • 第一步:0 - 5 = -5
  • 第二步:-5 + 3 = -2
  • 第三步:-2 - 2 = -4

这一路下来,出现过的最小库存是 -5。 说明如果你一开始真是 0 箱,那第一个操作就已经欠了 5 箱货。

那怎么办?很简单,把初始库存调到 5,就能把整条曲线整体往上抬 5。

  • 原来最惨是 -5,整体加 5 之后,就变成了 0
  • 其他时刻自然也都不可能再是负数了

所以,这个题就变成一句话:

先假设从 0 开始跑一遍操作,找出「最小前缀和」, 初始库存 = max(0, - minPrefixSum)。

为啥要跟 0 比一次呢?因为如果所有前缀和都 ≥ 0,那你从 0 开始就不亏,本来就不会出现负数,那初始库存就可以是 0,不用囤货。

代码我给你写得清爽一点,你一眼能看明白的那种:

publicclassWarehouseManager{

/**
     * 计算最少需要多少初始库存,才能保证过程中库存不为负
     * @param ops 每一步的操作,正数代表入库,负数代表出库
     * @return 最少初始库存
     */

publicstaticintminInitialStock(int[] ops){
int cur = 0;         // 当前库存(从 0 假装开始)
int minPrefix = 0;   // 记录一路上最惨的那个库存

for (int op : ops) {
            cur += op;       // 执行这一笔操作
if (cur < minPrefix) {
                minPrefix = cur; // 更新「最小前缀和」
            }
        }

// 如果一路都没跌破 0,那初始库存可以是 0
// 如果最小前缀和是 -k,那就至少要准备 k 箱货
return Math.max(0, -minPrefix);
    }

publicstaticvoidmain(String[] args){
// 举个例子:一天的操作
int[] ops = newint[] { -5, 10, -3, -4, 6 };

int startStock = minInitialStock(ops);
        System.out.println("最少需要的初始库存是: " + startStock);

// 验证一下全过程库存是不是都 >= 0
int stock = startStock;
for (int i = 0; i < ops.length; i++) {
            stock += ops[i];
            System.out.println("第 " + (i + 1) + " 步后库存:" + stock);
        }
    }
}

随便帮你脑补一下这组数据怎么跑的:

  • ops = { -5, +10, -3, -4, +6 }

  • 从 0 开始跑一遍:

    • 第 1 步:-5
    • 第 2 步:5
    • 第 3 步:2
    • 第 4 步:-2
    • 第 5 步:4

一路最惨的是 -5,所以答案是 5。 也就是,你一开始至少要有 5 箱货,仓库今天就不至于「透支」。

顺带再看下时间和空间

这个算法还挺划算的:

  • 只遍历了一遍数组,时间复杂度 O(n)
  • 只用了几个 int 变量,空间复杂度 O(1)

在面试里这种题一般就属于:别想复杂了,稳稳地写个前缀和就完事。

稍微加点工作味的扩展

真实仓库里,经理可能还会关心一个问题: “我仓库最大得准备多大容量,才不会爆仓?”

这个也能顺手算出来:

  • 还是从 0 开始走一遍
  • 这次不光记「最小前缀和」,也记一下「最大前缀和」
  • 当你选好了初始库存 start = max(0, -minPrefix)
  • 那一整天中出现过的最大库存就是 start + maxPrefix

你要是愿意,可以把上面代码再加两个变量就搞定,不过题目没要求的话,就当自己心里有数就行。

差不多就这样,这个题在很多面试里会换个壳子出现,比如银行账户、能量值、游戏血量什么的,其实背后都是这一个套路: 先从 0 开始跑,找到「最惨那一下」,再把整条曲线整体抬上去。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

最后给大家分享一份不错的副业资料,点击下方公众号,回复关键字: 副业 领,也可以链接我微信:hls404