程序员老鬼

我月薪15k,跳槽张口要到25k,我淡定说回去琢琢,结果隔天HR甩来消息:薪资能给到 35k,我却瞬间打了退堂鼓

刚看到个贴子:楼主月薪15k,跳槽面谈直接要25k,本来只是抱着试试的心态。结果HR第二天回消息:35k也能给。楼主反而慌了,开始打退堂鼓。

Image

我的看法是,薪资谈判别只盯数字。对方给得越高,你越要冷静:问清楚加班、绩效、职责边界、团队情况,再对照一下行业价位和自己能力,算个“性价比”。别因为害怕“配不上”就往回缩,也别被高薪一冲动就签了。

从我的角度看,最稳的路径还是先提升可替代价值,再大胆谈钱。敢要,也敢接,底气才是真的。

面试题:最接近的三数之和

那我就直接说哈,不整那些虚的。

昨晚十一点多,我在公司楼下便利店啃泡面,我们组那个小李突然微信问我:“哥,那个最接近三数之和咋写啊?我指针总乱飞。”我一看题目,嘿,就是 LeetCode 上那个 3Sum Closest。

题目意思翻一下人话就是: 给你一个 int 数组 nums,再给一个目标值 target,你在数组里随便挑三个数,算个和,让这个和尽量靠近 target,最后把这个和返回。必须真从数组里挑三个,不能自己瞎编。

你可以脑补一下生活场景,比如你要配服务器预算,有一堆机器价格,领导说“给我选三台,总价离 10 万块最近”,其实就是这个题,只是把价格换成整数而已。之前压数据库压测的时候,也有类似的“凑最接近容量”的小需求,也是这么个味道

我当时跟小李说:这个题看起来像暴力枚举三重循环,但那样是 O(n³),数组一大直接把你干趴下。其实有个老熟人套路:先排序,再双指针。

大概思路我用口水话讲一遍哈:

  • 先把数组排序,这一步很关键,排序完了之后,小的在前,大的在后。
  • 外层固定一个下标 i,认为 nums[i] 是第一个数。
  • 剩下两个数,用典型两端夹逼:左指针 l = i + 1,右指针 r = n - 1。
  • 每次算一下 sum = nums[i] + nums[l] + nums[r],看看和目标 target 差多少。 用一个变量 closest 记住到目前为止“最接近的那个和”。
  • 如果 sum 比 target 小,那要让和变大一点,就把左指针右移。 如果 sum 比 target 大,那就把右指针左移,让和小一点。
  • 差值要是刚好 0,那就别想了,直接可以返回 target 了,再怎么接近也就这样了。

为啥排序之后可以这么贪?因为排序完了以后,移动左指针只会让和变大,移动右指针只会让和变小,这个趋势是单调的,你才能有“往哪边挪更接近”的直觉,不然就全乱成一锅粥了。

细节上有几个小点,容易写着写着就骂人那种:

  • closest 初始化要稍微注意下,可以先随便取前三个的和,比如排序后 nums[0] + nums[1] + nums[2] 当初始值。
  • 记得取绝对值比较差距:Math.abs(sum - target) 和 Math.abs(closest - target)。
  • 数组长度小于 3 的话,这题本身一般默认不会给这种输入,但你自己写方法可以稍微防一手。

我给你整一份完整的 Java 代码,你直接能丢到本地跑的那种:

publicclassSolution{

publicintthreeSumClosest(int[] nums, int target){
// 保险一点,数组太短直接抛
if (nums == null || nums.length < 3) {
thrownew IllegalArgumentException("数组长度必须 >= 3");
        }

// 1. 先排序
        java.util.Arrays.sort(nums);

// 2. 用前三个先凑一个初始的 closest
int n = nums.length;
int closest = nums[0] + nums[1] + nums[2];

// 3. 枚举第一个数的下标 i
for (int i = 0; i < n - 2; i++) {
int left = i + 1;
int right = n - 1;

// 双指针往中间夹
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];

// 更新一下目前为止最接近的和
if (Math.abs(sum - target) < Math.abs(closest - target)) {
                    closest = sum;
                }

// 精准命中,直接可以收工了
if (sum == target) {
return target;
                } elseif (sum < target) {
// 和太小,左边往右挪,让和变大
                    left++;
                } else {
// 和太大,右边往左挪,让和变小
                    right--;
                }
            }
        }

return closest;
    }

// 随手写个 main 做个小测试
publicstaticvoidmain(String[] args){
        Solution s = new Solution();
int[] nums = {-1, 2, 1, -4};
int target = 1;
int ans = s.threeSumClosest(nums, target);
        System.out.println(ans); // 输出 2,离 1 最近
    }
}

这个实现时间复杂度就是排序 O(n log n) 加上双指针枚举 O(n²),总体 O(n²),空间上就排序用的那点儿,算比较省心的做法了。

小李昨天看完代码就“哦——原来我指针瞎跑的原因是没排序”,然后回家打游戏去了,留我一个人在工位上改 bug……行吧先这样,我去喝口水,等会你要是想顺手扩展成“四数之和”那一类,我们再唠。

-END-

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