面试了个36岁的大哥,技术底子那是真硬,架构设计头头是道,甚至还能手写源码,才18k。结果HR那边直接卡住。。
刚看到个贴子,大概意思就是:36岁技术大哥实力贼强,价钱也不高,结果被HR一句“潜力不够、性价比低”给刷了。
从我的角度看,问题根本在于——很多公司把“潜力”当遮羞布,实质还是怕承担成本。年轻人便宜,好管;老员工稳,但一旦涨薪空间不大,公司就觉得“不划算”。
说白了,就是只看长期投入,不看当下价值。
但换个角度想,一个能马上上手、架构写得明明白白的人,不比带一个啥都不懂的新人省心?培养新人那才是真成本啊。
公司算账,我们也得算自己的账。遇到看不见你价值的地方,那就换个地方发光。
面试题:三个数的最大乘积
说这个算法题之前,你先想象个场景:面试官递过来一张纸,上面只写了一句——“给你一堆整数,求三个数的最大乘积”。看着很眼熟对吧,但真要写代码,很多人第一反应都是:排序,然后取最大的三个数相乘,完事儿。结果一提交,测试用例全是负数,直接跪。
简单翻一下题目要求(用自己的话说一遍):
输入:一个整型数组 int[] nums,长度至少是 3输出:从里面选 三个数,让乘积尽可能大,返回这个乘积(一个 int)
这里有两个容易被忽略的点:
数组里可能有 负数 也可能 全是负数,或者负数和正数混在一起
一旦有负数,直觉就不太靠谱了,因为两个负数相乘会变成大大的正数,这就变好玩了。
排序版
如果不考虑性能,最直观的写法其实就两步:
把数组从小到大排序
最大乘积只可能是两种情况之一:
最后三个数: nums[n-1] * nums[n-2] * nums[n-3]最小的两个数(可能是很小的负数)乘以最大的那个数: nums[0] * nums[1] * nums[n-1]
然后取这两个里的最大值就行。
为啥要看最小两个?想象一下:[-10, -10, 1, 2, 3]如果只看后三个数:1 * 2 * 3 = 6但如果用两个最小的:(-10) * (-10) * 3 = 300,明显大多了。
这个方案的时间复杂度是 O(n log n),多数场景已经够用了。
不排序,线性扫描搞定
如果面试官继续追问:“能不能做到 O(n)?”,其实也不难,核心就是一边遍历一边维护 5 个变量:
三个最大的数: max1 >= max2 >= max3两个最小的数: min1 <= min2
最后同样是比较两种情况:
max1 * max2 * max3max1 * min1 * min2
代码大概是这样(Java 版):
publicclassMaxProductOfThree{
publicintmaximumProduct(int[] nums){
// 至少要有三个数,防御一下
if (nums == null || nums.length < 3) {
thrownew IllegalArgumentException("数组长度必须 >= 3");
}
// 初始化:最大值用 Integer.MIN_VALUE,最小值用 Integer.MAX_VALUE
int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE;
int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
for (int x : nums) {
// 更新前三大
if (x >= max1) {
max3 = max2;
max2 = max1;
max1 = x;
} elseif (x >= max2) {
max3 = max2;
max2 = x;
} elseif (x >= max3) {
max3 = x;
}
// 更新最小两个
if (x <= min1) {
min2 = min1;
min1 = x;
} elseif (x <= min2) {
min2 = x;
}
}
int product1 = max1 * max2 * max3;
int product2 = max1 * min1 * min2;
return Math.max(product1, product2);
}
// 简单测一下
publicstaticvoidmain(String[] args){
MaxProductOfThree s = new MaxProductOfThree();
System.out.println(s.maximumProduct(newint[]{1, 2, 3})); // 6
System.out.println(s.maximumProduct(newint[]{1, 2, 3, 4})); // 24
System.out.println(s.maximumProduct(newint[]{-10, -10, 1, 2, 3})); // 300
System.out.println(s.maximumProduct(newint[]{-5, -4, -3, -2, -1})); // -6
}
}
这一段逻辑稍微捋一下就很好懂:
扫一遍数组,顺手维护当前见过的前三大 & 两个最小
遍历结束后,所有可能成为“答案组合”的数都在这 5 个变量里了
为啥一定是这两种组合?
要想乘积大,要么“三个特别大的正数” 要么是“一个特别大的正数 + 两个特别小的负数”(负负得正)
几个常见的疑问:
数组刚好只有三个数?那就正常走一遍逻辑,最后其实就是这三个数的乘积。
全是负数怎么办?比如
[-5, -4, -3, -2]
三个最大值: -2, -3, -4→ 乘积-24max1 + 两个最小: -2 * -5 * -4 = -40取最大的是-24,符合预期。
会不会溢出?题目如果是 LeetCode 那种,一般默认结果在 int 范围里。如果你不放心,可以把中间乘积改成 long 算,再转回 int 或直接返回 long。
这题的“坑”其实就一个:要记得负数也能帮你变大。 实现上,用 Java 写个线性扫描,维护“三大两小”,最后对比两种乘积就行了,既清晰又高效,面试拿来当模板非常合适。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html