程序员老鬼

放弃华为16级,进了体制内一个非常清闲的部门,早八晚五,原以为会越来越好,结果发现工作没意义,工资也不好看,后悔了

刚看到个贴子:有网友吐槽,说自己放弃华为16级,跑去体制内一个特别清闲的部门,本以为日子会越过越舒服,结果发现工作像在养老,工资也一般,现在开始后悔了。

Image

网友回帖里有说“清闲就是最大的福利”,也有人说“华为的强度不是人人扛得住”。但在我看来,这哥们的问题不是体制不好,也不是华为多香,而是预期和现实不匹配。

怎么说呢,清闲久了,人确实容易空虚;收入低久了,人也会焦虑。就像买菜一样,便宜的没味道,好吃的又心疼钱,想两头都占,只能越来越纠结。

从我的角度看,后悔不是坏事,说明他开始重新审视自己真正想要什么。体制内不一定不能发展,大厂也不是只有高压才能活。关键是找到适合自己的节奏,再做选择。【备注:文末可领最新资料】

面试题:旋转函数

昨天晚上十一点多我还在公司,正准备关电脑回家,结果我们组那个小李突然在后面喊我:东哥东哥,你懂不懂那个“旋转函数”的题啊,我这破题 O(n²) 老是超时。嗯……本来已经站起来拿包了,只能又坐回去给他画了半个白板。

先把题意思捋一下哈,用大白话说: 有个数组 nums,长度是 n,比如 [4,3,2,6]。定义一个东西叫 F(k):把数组向右旋转 k 步,然后用下标乘以对应元素求和。

比如不旋转的时候(k = 0):

  • 还是 [4,3,2,6]
  • F(0) = 04 + 13 + 22 + 36 = 0 + 3 + 4 + 18 = 25

右旋一步(k = 1),数组变成 [6,4,3,2]:

  • F(1) = 06 + 14 + 23 + 32 = 0 + 4 + 6 + 6 = 16

题目就是:所有的 F(k) 里面,最大的那个是多少。

小李一开始写的就是最直觉那种:每次真的把数组旋转一遍,然后再扫一遍算和。代码也挺“教科书”的那种,时间复杂度直接 n * n,数组一长立马超时,他人都麻了。

我当时跟他说,你想象一下,如果每次 F(k) 都从头算起,肯定浪费。关键是要找到 F(k) 和 F(k-1) 的关系,这样就能一边转一边更新结果,不用每次重来。

你看啊,先把几个量记一下:

  • 总和 sum = nums[0] + nums[1] + ... + nums[n-1]
  • F(0) 很好算:F(0) = 0*nums[0] + 1*nums[1] + ... + (n-1)*nums[n-1]

重点来了,F(k) 和 F(k-1) 怎么关系起来?

别急着看公式,你脑子里先过一遍旋转的画面: 右旋一次,相当于最后一个元素被挪到最前面,其他的下标都 +1。

拿 [4,3,2,6] 举个例子:

  • F(0):按原数组算
  • 右旋一次得到 [6,4,3,2] 是 F(1)
  • 再右旋一次 [2,6,4,3] 是 F(2)

这时候可以这么想: 从 F(k-1) 变成 F(k),发生了两件事:

  1. 每个元素的下标都 +1,所以“整体”会多加一遍数组总和 sum。
  2. 但是有一个倒霉孩子从下标 n-1 被挪到了下标 0,它原来贡献是 (n-1) * value,现在贡献变成 0 * value,等于少了 (n * value) 那么多(因为刚才那一步“整体 + sum”里面已经把它算成 +value 了,要把多出来的 n*value 扣掉)。

于是就得到了那个经典关系式(我口述一下,你自己脑补下):

F(k) = F(k-1) + sum - n * nums[n - k]

注意这里 nums[n - k] 是右旋第 k 次时,被“挪到最前面”的那个元素。本质就是,右旋 k 次,其实就是把原数组最后 k 个元素搬到前面。

有了这个关系,整件事就好办了:

  • 先把 sum 求出来
  • 计算一遍 F(0)
  • 然后从 k=1 到 n-1,用上面的递推式滚着算下去,顺手维护一个最大值

复杂度就从 O(n²) 直接变成 O(n),面试官一般看到你能把这题讲到这个程度,脸上表情都会柔和很多,哈哈。

我当时就随手给小李写了个 Java 版本,大概像下面这样,你可以直接拿去用:

publicclassRotateFunction{

// 主方法:给一个数组,返回最大旋转函数值
publicintmaxRotateFunction(int[] nums){
int n = nums.length;
if (n == 0) return0;
if (n == 1) return0; // 只有一个元素,怎么转都一样,下标永远是 0

long sum = 0;     // 数组元素总和
long f0 = 0;      // F(0)
for (int i = 0; i < n; i++) {
            sum += nums[i];
            f0 += (long) i * nums[i];
        }

long max = f0;
long curr = f0;   // 当前 F(k) 的值,从 k=0 开始滚

// 按照公式:F(k) = F(k-1) + sum - n * nums[n - k]
for (int k = 1; k < n; k++) {
            curr = curr + sum - (long) n * nums[n - k];
if (curr > max) {
                max = curr;
            }
        }

return (int) max;
    }

// 随便写个 main 测一下
publicstaticvoidmain(String[] args){
        RotateFunction rf = new RotateFunction();
int[] nums = {4, 3, 2, 6};
        System.out.println(rf.maxRotateFunction(nums)); // 输出 26
    }
}

顺带说一句,上面我用的是 long,不是故意装专业,纯粹是防止有些测试数据特别大,下标乘元素的时候把 int 撑爆了,踩过坑的人都懂那种“代码看着没问题但结果就是不对”的绝望。

小李看完白板推导,再看这段代码,大概五分钟就完全想明白了,然后很开心地对我说:行了东哥你快回去睡觉吧,我自己再刷两道。 我看了看时间,都快半夜了,就顺口回他一句:别刷了,早点回去休息,明天精神好一点,旋转函数也转得快一点……

-END-

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

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