程序员老鬼

南大计算机博士,毕业两年多,在北京某头部大厂,接着干还是回二线老家央企??

刚刷到这个帖,我第一反应是:这不就是打工人经典分岔路吗。

南大计算机博士,在北京头部大厂,两年多,年包六七十万,听着挺香。但问题是方向不在AI风口,业务也没啥增量,晋升看不到,日常还要oncall。钱是多,可人一直被吊着,心里累也正常。

Image

现在老家二线省会有个央企研究院,钱直接腰斩,二十多到三十万。但人家给的是另一套东西:考核期过了能入编,女友也在本地事业编,未来结婚买房生活都能落地。

这事真不是单纯比工资。北京大厂给的是现金流和平台,老家央企给的是稳定、关系和生活节奏。关键看他还想不想继续在互联网熬。要是已经对业务没感觉,晋升也卡着,那回去未必是退路,可能是及时下车。

今日面试题

数组是这样的:

[2, 6, 4, 8, 10, 9, 15]

只要把中间这一段排一下序,整个数组就有序了:

[6, 4, 8, 10, 9]

题目问的不是怎么排序,而是这段最短子数组到底有多长。

这个题我第一眼不会先去复制一份数组排序。那种写法当然能过,但有点笨,还多吃一份空间。现场写代码我一般先看“哪里破坏了有序性”。

从左往右扫,维护一个当前见过的最大值。

如果当前位置的数比最大值还小,说明它站错了位置,右边界至少要扩到这里。

比如扫到 4 的时候,前面最大值是 6,4 < 6,右边界就出来了。

继续扫到 9,前面最大值是 10,9 < 10,右边界继续往后挪。

这一步能找到右边界。

但左边界还不够。因为左边界要看右侧有没有更小的数。

所以再从右往左扫,维护一个当前见过的最小值。

如果当前位置的数比最小值还大,说明它也站错了,左边界要往这里收。

代码我会这么写,不绕:

classSolution{
publicintfindUnsortedSubarray(int[] nums){
if (nums == null || nums.length < 2) {
return0;
        }

int right = -1;
int maxSeen = nums[0];

for (int i = 1; i < nums.length; i++) {
if (nums[i] < maxSeen) {
                right = i;
            } else {
                maxSeen = nums[i];
            }
        }

if (right == -1) {
return0;
        }

int left = 0;
int minSeen = nums[nums.length - 1];

for (int i = nums.length - 2; i >= 0; i--) {
if (nums[i] > minSeen) {
                left = i;
            } else {
                minSeen = nums[i];
            }
        }

return right - left + 1;
    }
}

拿刚才的数组跑一下:

nums = [2, 6, 4, 8, 10, 9, 15]

从左往右:

2 正常
6 正常
4 < 6   right = 2
8 正常
10 正常
9 < 10  right = 5
15 正常

右边界是 5。

从右往左:

15 正常
9 正常
10 > 9  left = 4
8 正常
4 正常
6 > 4   left = 1
2 正常

左边界是 1。

所以长度就是:

5 - 1 + 1 = 5

这题真正容易写错的地方,是只找一个方向。

只从左往右,你只能知道右边界。只从右往左,你只能知道左边界。两个方向都扫一遍,问题就很干净。

时间复杂度 O(n),空间复杂度 O(1)。

不需要排序,也不需要额外数组。这个写法在线上看也舒服,边界少,判断顺序也不容易埋坑。