39岁,被大厂裁员,月薪两万多的收入瞬间清零。这事放以前,评论区恐怕已经炸开了锅,中年危机、房贷车贷、孩子教育,每一条都足以让人焦虑。但这次的主人公,却选择了一种截然不同的应对方式:他不再投简历,不再卷面试,而是回归家庭,每天接送孩子、买菜做饭,家庭主要收入依靠妻子每月6000元的工资。

有人觉得这是“逃避现实”,也有人认为“能睡安稳觉就算赢了”。这件事背后真正扎心的地方,或许不在于收入从两万多降到六千,而在于很多人拼搏半生后才发现,那份高薪买来的,常常是加班、脱发和一肚子无处发泄的憋闷。
你说他没出息?他现在能按时吃饭、陪伴家人,整个人的状态反而比上班时更松弛。很多人嘴上调侃他“吃软饭”,但如果真让他们去过那种不用随时回复消息、不用为项目背锅的日子,未必舍得放弃。
生活的赛道不止一条,技术的解法也往往不止一种。就像下面这道经典的算法面试题,看似简单,却能考验出不同的解题思路和深度。
面试题:寻找重复数
题目是这样的:给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 的范围内。假设只有一个重复的整数,找出这个重复的数。
很多人一上来就想用 HashSet 去重,这个方法当然可行,但往往不是面试官最期待的答案。因为这道题的隐含约束——数组长度和取值范围的特定关系——暗示着存在更巧妙的、空间复杂度更优的解法。
最经典的思路,是将这个问题转化为“链表找环”问题。
为什么可以这么转化?因为数组的索引和值构成了一个隐式的映射关系。从索引 0 出发,nums[0] 指向下一个位置,下一个位置的值又指向再下一个位置……每个位置都唯一指向下一个位置,这结构就像一条单链表。既然有数字重复,就意味着有两个不同的索引指向了同一个值,从而在这个隐式链表中形成了一个环。
如果一上来就排序,会修改原数组;用 HashSet,空间复杂度就是 O(n)。面试官出这道题,多半是想考察在 O(1) 额外空间内的解决方案。
下面是用 Java 实现“快慢指针法”的代码:
public class FindDuplicateNumber {
public int findDuplicate(int[] nums) {
int slow = nums[0];
int fast = nums[0];
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
int p1 = nums[0];
int p2 = slow;
while (p1 != p2) {
p1 = nums[p1];
p2 = nums[p2];
}
return p1;
}
public static void main(String[] args) {
FindDuplicateNumber solver = new FindDuplicateNumber();
int[] nums = {1, 3, 4, 2, 2};
System.out.println(solver.findDuplicate(nums)); // 输出:2
}
}
代码逻辑分为清晰的两步:
第一步,快慢指针赛跑,目的是证明环的存在并找到环内的一个相遇点。注意这里使用了 do...while 循环,因为初始时快慢指针位于同一起点,需要先移动一次再判断。
第二步,将一个指针移回链表头部(nums[0]),另一个指针留在相遇点。然后两个指针都以相同速度(每次一步)前进,它们再次相遇的节点,就是环的入口,也就是我们要找的重复数字。
以 nums = [1,3,4,2,2] 为例,其隐式链表路径如下:
// 路径示意
0 -> 1 -> 3 -> 2 -> 4 -> 2 -> 4 ...
可以看到,在值 2 和 4 之间形成了环,而环的入口 2 正是那个重复的数字。
这道题有个容易混淆的点:起点是 0 还是 nums[0]?上面的写法直接从 nums[0] 开始,将数组值视为下一个节点的“地址”,思维更直接,避免了在“索引”和“值”之间反复转换。
最终,这个算法的时间复杂度是 O(n),额外空间复杂度是 O(1),完美契合题目对空间的要求。它没有修改原数组,也没有使用额外的集合,纯粹通过指针的追逐关系就找到了答案。这种题表面是数组操作,内核其实是数学映射与链表思想的结合,非常考验解题者的洞察力。
无论是职业选择还是技术解题,有时候跳出常规的“卷”式思维,换一个角度审视约束条件,反而能找到更优、更让自己舒适的路径。如果你对这类技术讨论或职业话题有更多想法,欢迎到云栈社区与更多开发者交流。