程序员老鬼

面试了个36岁的大哥,技术底子那是真硬,架构设计头头是道,甚至还能手写源码,才18k。结果HR那边直接卡住。。

刚看到个贴子,大概意思就是:36岁技术大哥实力贼强,价钱也不高,结果被HR一句“潜力不够、性价比低”给刷了。

Image

从我的角度看,问题根本在于——很多公司把“潜力”当遮羞布,实质还是怕承担成本。年轻人便宜,好管;老员工稳,但一旦涨薪空间不大,公司就觉得“不划算”。

说白了,就是只看长期投入,不看当下价值。

但换个角度想,一个能马上上手、架构写得明明白白的人,不比带一个啥都不懂的新人省心?培养新人那才是真成本啊。

公司算账,我们也得算自己的账。遇到看不见你价值的地方,那就换个地方发光。

面试题:三个数的最大乘积

说这个算法题之前,你先想象个场景:面试官递过来一张纸,上面只写了一句——“给你一堆整数,求三个数的最大乘积”。看着很眼熟对吧,但真要写代码,很多人第一反应都是:排序,然后取最大的三个数相乘,完事儿。结果一提交,测试用例全是负数,直接跪。

简单翻一下题目要求(用自己的话说一遍):

  • 输入:一个整型数组 int[] nums,长度至少是 3
  • 输出:从里面选 三个数,让乘积尽可能大,返回这个乘积(一个 int)

这里有两个容易被忽略的点:

  1. 数组里可能有 负数
  2. 也可能 全是负数,或者负数和正数混在一起

一旦有负数,直觉就不太靠谱了,因为两个负数相乘会变成大大的正数,这就变好玩了。

排序版

如果不考虑性能,最直观的写法其实就两步:

  1. 把数组从小到大排序

  2. 最大乘积只可能是两种情况之一:

  • 最后三个数: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 * max3
  • max1 * 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 个变量里了

  • 为啥一定是这两种组合?

    • 要想乘积大,要么“三个特别大的正数”
    • 要么是“一个特别大的正数 + 两个特别小的负数”(负负得正)

几个常见的疑问:

  1. 数组刚好只有三个数?那就正常走一遍逻辑,最后其实就是这三个数的乘积。

  2. 全是负数怎么办?比如 [-5, -4, -3, -2]

  • 三个最大值:-2, -3, -4 → 乘积 -24
  • max1 + 两个最小:-2 * -5 * -4 = -40取最大的是 -24,符合预期。
  • 会不会溢出?题目如果是 LeetCode 那种,一般默认结果在 int 范围里。如果你不放心,可以把中间乘积改成 long 算,再转回 int 或直接返回 long。

  • 这题的“坑”其实就一个:要记得负数也能帮你变大。 实现上,用 Java 写个线性扫描,维护“三大两小”,最后对比两种乘积就行了,既清晰又高效,面试拿来当模板非常合适。

    -END-

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

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