连续两个月裁员,果然没逃过。心情还行,因为我旁边的博士也被裁了。。
连续两个月裁员,楼主本来还想着自己能不能混过去,结果最后还是没逃掉。但他居然说心情还行,原因也很离谱:坐旁边那个博士也一起被裁了。
这话一看就懂了。不是幸灾乐祸,是那种“哦,原来不是我不行”的松一口气。你学历高也好,能力强也好,坐工位旁边写论文出身也好,到了公司要缩人的时候,很多时候真不是看谁更努力。
打工人最怕的不是被裁,是被裁完还开始怀疑自己:是不是我太菜,是不是我不够拼。结果一看,博士也在名单里,心里反而踏实了点。
职场有时候就这么荒诞,安慰你的不是领导的话,也不是HR的补偿包,而是旁边大佬也没跑掉。哈哈
数组长这样:
[0, 2, 5, 9, 7, 3, 1]
峰顶是 9,下标是 3。
这个题叫“山脉数组的峰顶索引”。第一眼看着很水,for 循环扫一遍,找到 arr[i] > arr[i - 1] && arr[i] > arr[i + 1] 就完事。
代码也能写:
classSolution{
publicintpeakIndexInMountainArray(int[] arr){
for (int i = 1; i < arr.length - 1; i++) {
if (arr[i] > arr[i - 1] && arr[i] > arr[i + 1]) {
return i;
}
}
return -1;
}
}
这代码没错。
但我一般看到这种题,不会先交这个版本。因为题目既然明确说了“山脉数组”,就等于把数组结构告诉你了:前半段严格递增,后半段严格递减。
这种结构不用白不用。
判断一个位置 mid 在山的哪一侧,其实只看它和右边一个数的关系就够了。
arr[mid] < arr[mid + 1]
说明还在上坡,峰顶一定在右边。
arr[mid] > arr[mid + 1]
说明已经到下坡了,峰顶可能就是 mid,也可能在左边。
这里容易写错的地方是右边界怎么收。
如果 arr[mid] > arr[mid + 1],不能写 right = mid - 1。因为 mid 自己有可能就是峰顶,直接丢掉就错了。
我会这么写:
classSolution{
publicintpeakIndexInMountainArray(int[] arr){
int left = 0;
int right = arr.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid] < arr[mid + 1]) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
}
这段代码有个细节:循环条件是 left < right,不是 left <= right。
因为我们不是在找某个固定值,而是在不断缩小峰顶所在的区间。等 left == right 的时候,区间里只剩一个位置,这个位置就是峰顶。
拿数组跑一下:
arr = [0, 2, 5, 9, 7, 3, 1]
left = 0, right = 6
mid = 3
arr[3] = 9, arr[4] = 7
9 > 7,说明 mid 已经在下坡起点,right = mid
left = 0, right = 3
mid = 1
arr[1] = 2, arr[2] = 5
2 < 5,说明还在上坡,left = mid + 1
left = 2, right = 3
mid = 2
arr[2] = 5, arr[3] = 9
5 < 9,继续往右,left = mid + 1
left = 3, right = 3
返回 3
复杂度也很干净。
顺扫是 O(n),二分是 O(log n)。
这题真正要注意的不是代码有多难,而是别把“山脉数组”这四个字当废话。题目给了结构,就说明可以靠结构砍掉一半搜索空间。
我见过不少人这里写成:
if (arr[mid] > arr[mid - 1] && arr[mid] > arr[mid + 1])
然后一堆边界判断。
不是不能写,但没必要。看 mid 和 mid + 1 的走势,代码反而更稳。山还在往上走,就去右边;山开始往下掉,就收右边界。
最后剩下的那个点,就是峰顶。