今天3月25号了,2026年第一个季度都快过完了。

今天看到一个帖子,一个技术经理,10年+经验,35岁被裁,java后端,现在面试都是外包,问:外包20k要不要去。
❝某后端开发:去啊。AI杀灭一切,能干一天是一天啊
❝某软通动力员工:我23k外包,965,活轻松不累,到点就走,上班可以干别的没人管
❝某深圳地铁员工:在你犹豫的时候,别人又赚钱了~过几年没得干了
❝某后端开发:外包高工资的,基本都要995或者996
看完这些评论,我陷入了沉思。
20k,在北京,不算高,但也不低。如果是在外包岗位,更不算低了。
但这个老哥纠结的,不是钱多钱少,而是:35岁java后端,现在只能选外包了吗?
这才是最扎心的。
想当年,java后端,那可是互联网的顶梁柱。什么微服务、分布式、Spring Cloud,学个java感觉自己天下无敌。现在呢?AI一来,代码都能自己写了,你java写得再好,能有AI快?
外包这个词,在以前那是给年轻人准备的。大厂招外包,是为了让年轻人进来干脏活累活,完了再踢出去。现在好了,35岁的正编也变成外包了。
所以这个老哥问的,不是20k要不要去,而是:外包干久了,还有未来吗?
评论区有人说"能干一天是一天",听起来挺消极的,但也是大实话。现在这个环境,你能保证自己35岁不被裁,但能保证40岁不被裁吗?50岁呢?
也有人说"在家歇着也不干",这话说得虽然糙,但理不糙。你不去外包,在家干嘛?送外卖?跑滴滴?还是躺平?
还有个老哥说"外包高工资的,基本都要996"。这倒是真的。外包公司之所以给高工资,是因为知道你能干活的时间有限。35岁外包,40岁怎么办?外包公司可不管你养老。
但话说回来,20k外包,总比8千的正编强吧?有钱总比没钱好。
一个小偷要偷房子里的钱,但相邻的房子在同一晚上会被报警。房子呈树形结构,每个节点代表一个房子,里面有一定金额的金银财宝。小偷不能偷两个相连的房子。
给定一棵二叉树,返回小偷能偷到的最大金额。
这题是House Robber系列的第三题,前两题是线性和环形数组,这题是树形结构。
暴力解法:尝试偷或者不偷每个节点,计算最大值。但会超时,因为有很多重复计算。
优化思路:动态规划 + 递归。
对于每个节点,我们有两种选择:偷或者不偷。
我们可以用一个数组来返回两种状态:[不偷当前节点的最大值, 偷当前节点的最大值]
对于根节点:
递归遍历整棵树,最后返回max(不偷根节点, 偷根节点)。
时间复杂度:O(n),每个节点只访问一次
空间复杂度:O(h),h是树的高度,递归调用栈的深度
package main
import (
"fmt"
)
// TreeNode 定义二叉树节点
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
// 返回数组:[不偷当前节点的最大值, 偷当前节点的最大值]
func rob(root *TreeNode) int {
if root == nil {
return0
}
result := dfs(root)
return max(result[0], result[1])
}
func dfs(node *TreeNode) [2]int {
if node == nil {
return [2]int{0, 0}
}
// 递归处理左右子树
left := dfs(node.Left)
right := dfs(node.Right)
// 不偷当前节点:可以偷左右子树
notRob := max(left[0], left[1]) + max(right[0], right[1])
// 偷当前节点:不能偷左右子树
rob := left[0] + right[0] + node.Val
return [2]int{notRob, rob}
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
// 方法二:使用哈希表缓存结果(更易理解)
func robWithMemo(root *TreeNode) int {
memo := make(map[*TreeNode]int)
return robHelper(root, memo)
}
func robHelper(node *TreeNode, memo map[*TreeNode]int) int {
if node == nil {
return0
}
// 检查缓存
if val, ok := memo[node]; ok {
return val
}
// 不偷当前节点
notRob := robHelper(node.Left, memo) + robHelper(node.Right, memo)
// 偷当前节点
rob := node.Val
if node.Left != nil {
rob += robHelper(node.Left.Left, memo) + robHelper(node.Left.Right, memo)
}
if node.Right != nil {
rob += robHelper(node.Right.Left, memo) + robHelper(node.Right.Right, memo)
}
result := max(notRob, rob)
memo[node] = result
return result
}
func main() {
// 构建测试树:[3,2,3,null,3,null,1]
// 3
// / \
// 2 3
// \ \
// 3 1
root := &TreeNode{
Val: 3,
Left: &TreeNode{
Val: 2,
Right: &TreeNode{Val: 3},
},
Right: &TreeNode{
Val: 3,
Right: &TreeNode{Val: 1},
},
}
result := rob(root)
fmt.Printf("最大偷窃金额: %d\n", result)
// 测试用例
testCases := []struct {
input *TreeNode
expected int
}{
{root, 7},
{&TreeNode{Val: 2, Right: &TreeNode{Val: 3}}, 3},
{&TreeNode{Val: 1}, 1},
{nil, 0},
}
for i, tc := range testCases {
result := rob(tc.input)
if result == tc.expected {
fmt.Printf("✓ 测试%d: %d\n", i+1, result)
} else {
fmt.Printf("✗ 测试%d: %d (expected: %d)\n", i+1, result, tc.expected)
}
}
}
这题的关键是想清楚状态:对于每个节点,要么偷要么不偷,取决于哪种选择能获得更大的收益。
35岁外包也是一个道理:要么去,要么不去,取决于哪种选择能让你的收益最大化。
去外包,虽然不是长久之计,但至少能拿到20k,能解燃眉之急。不去外包,可能连20k都没有。
所以啊,别想太多,能赚钱就先赚着。船到桥头自然直,车到山前必有路。
35岁又怎样?java又怎样?只要还能干活,就有价值。AI再厉害,也需要人来给它喂数据、调模型、优化prompt。