刚看到个贴子,说男生一年140万,女朋友一年15万,差了快10倍,谈了两年,越看越不顺眼,纠结要不要换一个。

我觉得这事吧,关键不在钱多少,而在你到底想要什么样的关系。你要的是“合作伙伴”,那确实会在意对方有没有共同承担生活的能力;你要的是“照顾与被照顾”,那收入差距就不是核心矛盾。怕的就是嘴上说不介意,心里天天拿工资单当显微镜。
换个角度想,现在嫌弃她15万,以后可能也会嫌弃别人30万、50万,“不顺眼”的借口永远能找到。说到底还是价值观问题:你是把伴侣当资产配置,还是当一起过日子的人
想象下,你有一堆整数,像是一桌子乱七八糟的账单,然后老板说: “从里面随便挑三个,加起来要尽量接近 target,看你能凑到多少。”
这就是算法题「最接近的三数之和」:
给定整数数组
nums和目标值target,从中选出三个数,使它们的和最接近target。 返回这个最接近的和(保证答案唯一)。
Go 版本函数一般长这样:
functhreeSumClosest(nums []int, target int)int我们要做的,就是把这个函数实现好。
最粗暴的办法其实也挺好理解: 三个数,对吧,那就三重循环,把所有 i < j < k 的组合都试一遍:
sumtarget 做差,看离得多近伪代码感觉就是:
best := 很大的值for ifor jfor k sum := nums[i] + nums[j] + nums[k] 如果比当前 best 更接近 target,就更新 best问题也很明显:时间复杂度是 O(n^3),数组一大,直接卡死,线上绝对不敢这么写。
常规思路是这样的:
nums[i]为啥排序之后好办? 因为排完序,数组是单调递增的,你就能通过比较当前和与 target 的大小,来决定是让左指针右移,还是右指针左移,从而让和变大或变小——这个在 Go 里很好写。
整个过程大概是:
对 nums 升序排序
初始化一个 bestSum 为任意一个合法的三数和(比如前 3 个相加),顺便记一个 minDiff,表示和 target 的最小差值
从 i = 0 遍历到 len(nums)-3,每次:
left := i+1,right := len(nums)-1sum := nums[i] + nums[left] + nums[right]|sum - target| 更小,就更新 bestSum 和 minDiffsum == target,那就直接可以返回了,因为不可能比这个更近sum < target,说明和太小了,让 left++sum > target,说明和太大了,让 right--时间复杂度就变成了:外层 O(n),内层双指针 O(n),合起来 O(n^2),这个在面试题里非常能打。
直接上 Go 源码,能复制就跑的那种:
package mainimport ("fmt""math""sort")functhreeSumClosest(nums []int, target int)int { n := len(nums)if n < 3 {// 正常 LeetCode 里不会给这种输入,这里简单兜个底panic("nums length must be at least 3") }// 先排序 sort.Ints(nums)// 初始化:随便取一个合法三元组当初始答案 bestSum := nums[0] + nums[1] + nums[2] minDiff := int(math.Abs(float64(bestSum - target)))for i := 0; i < n-2; i++ { left, right := i+1, n-1for left < right { sum := nums[i] + nums[left] + nums[right] diff := int(math.Abs(float64(sum - target)))if diff < minDiff { minDiff = diff bestSum = sum }if sum == target {// 已经是最理想的情况了return sum } elseif sum < target {// 和偏小,左指针右移,试图让和变大 left++ } else {// 和偏大,右指针左移,试图让和变小 right-- } } }return bestSum}funcmain() { nums := []int{-1, 2, 1, -4} target := 1 fmt.Println(threeSumClosest(nums, target)) // 输出 2,因为 -1 + 2 + 1 = 2}可以注意几个小细节:
minDiff 用的是 math.Abs,但 math.Abs 的参数是 float64,所以要转来转去一圈bestSum 用的是 nums[0] + nums[1] + nums[2],这样一来后面就不需要写「这是第一轮,先赋值」这种分支就这样,这题搞定,你可以先自己敲一遍,顺手多打几个不同的 nums 和 target 试试,感觉一下双指针怎么在数组里“滑”起来的。
🔥虎哥私藏精品🔥
虎哥作为一名老码农,整理了全网最全《GO后端开发资料合集》。总量高达650GB。