leecodecode【树形DP】【2026.6.11打卡-java版本】

打家劫舍 III

要点:节点是两个状态

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //节点是两个状态
    public int rob(TreeNode root) {
        int[] res = dfs(root);
        return Math.max(res[0], res[1]);
        
    }

    private int[] dfs(TreeNode node){
        if(node  == null){
            return new int[]{0,0};
        }

        int[] left = dfs(node.left);
        int[] right = dfs(node.right);
        int rob = left[1]+right[1]+node.val;
        int norob = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        return new int[]{rob, norob};
    }
}

监控二叉树

要点:分三种情况讨论,int\[\]

java 复制代码
class Solution {
    public int minCameraCover(TreeNode root) {
        int[] res = dfs(root);
        return Math.min(res[0], res[2]);
    }

    private int[] dfs(TreeNode node) {
        if (node == null) {
            return new int[]{Integer.MAX_VALUE / 2, 0, 0}; // 除 2 防止加法溢出
        }
        int[] left = dfs(node.left);
        int[] right = dfs(node.right);
        int choose = Math.min(left[0], left[1]) + Math.min(right[0], right[1]) + 1;
        int byFa = Math.min(left[0], left[2]) + Math.min(right[0], right[2]);
        int byChildren = Math.min(Math.min(left[0] + right[2], left[2] + right[0]), left[0] + right[0]);
        return new int[]{choose, byFa, byChildren};
    }
}

随机知识

核心题**:什么是死信队列?怎么利用它实现延迟队列?

面试官为什么这么问?

死信队列是 RabbitMQ 实现可靠服务的兜底方案,延迟队列则是定时任务的异步实现。我问这个是想看你会不会用 RabbitMQ 的特性实现业务需求,比如下单未支付自动取消。

希望听到怎样的回答:

  • 死信(Dead Letter) :消息在以下情况会变成死信:
    1. 被消费者 basicReject 或 basicNack 且 requeue=false。
    2. 消息 TTL 过期。
    3. 队列已满,无法入队。
  • 死信交换机(DLX) :在声明队列时可以指定 x-dead-letter-exchange,消息成为死信后会被重新路由到指定的死信交换机,再进入绑定队列,供专门消费者处理(记录日志、重试、人工介入)。
  • 延迟队列实现 :RabbitMQ 本身没有延迟队列,但可以通过 TTL + DLX 组合实现:
    1. 声明一个普通队列,设置消息 TTL(或者设置队列 TTL)。
    2. 该队列不设消费者,消息过期后自动成为死信。
    3. 死信被路由到真正处理的队列,消费者从那里消费,就实现了"延迟"消费。
  • 结合项目:"我们面经 Agent 中,用户请求生成一份模拟面试,如果大模型服务暂时不可用,我们会把请求放入一个带 TTL 的消息,如果 30 秒内没被成功消费,就自动转入死信,通知用户稍后重试。"

候选人

好的。这个问题分为两部分:死信队列的概念和生成条件,以及如何巧妙地用 TTL + 死信队列实现延迟队列。我从死信的基本概念讲起,然后说明延迟队列的实现原理,最后结合项目场景举例。

第一,消息怎么变成死信。

死信其实就是"正常队列里待不下去"的消息。RabbitMQ 定义了三种情况,消息会被转成死信:

一是消费者拒绝且不让消息重回队列。 消费者收到消息后发现处理不了、格式错误或者重试次数已经耗尽,调 basicNackbasicReject 返回,同时把 requeue 设为 false。消息被标记为"不回去了",变成死信。

二是消息 TTL 过期。 发送消息时设了存活时间,或者队列设了 TTL 属性,消息在队列里等待超时还没被消费,RabbitMQ 自动判定它过期,成为死信。

三是队列满了。 队列设置了最大长度,新消息过来时队列已经满了,最老的消息会被"挤出去",也变成死信。

这三种情况下的死信会被重新交给一个特殊的交换机处理,就是死信交换机(DLX) 。声明队列时加参数 x-dead-letter-exchange,指定死信的"回收站",消息成了死信后,原来的队列把消息原封不动(还会带上一些死信相关的 header)重新路由到死信交换机,再进入绑定的死信队列,等待专门消费者做善后处理------记录异常、发送告警、人工补偿。

第二,怎么用死信队列实现延迟队列。

RabbitMQ 自身没有直接支持"等 30 秒再投递"这种延迟队列,但可以通过 TTL + DLX 这个组合巧妙实现。

做法是创建两个队列:

一个是"延时队列"。 这个队列本身不配消费者,只设两个关键属性:x-message-ttl 指定消息存活时间(或发消息时设 expiration),以及 x-dead-letter-exchange 指向真正的业务交换机。消息进入这个队列后,就静静等待 TTL 到期。

一个是"业务处理队列"。 这个队列正常绑定消费者。当延时队列里的消息 TTL 过期、变成死信后,RabbitMQ 自动把这条死信转发到业务交换机,再路由到业务处理队列。消费者从这个业务处理队列拿到消息时,TTL 时间已经过去,达到了延迟消费的效果。

举个例子:订单 30 分钟未支付自动取消。下单后发消息到延时队列,设 TTL 30 分钟。这 30 分钟内消息搁在延时队列里等过期,时间一到自动转死信,路由到业务处理队列,消费者收到消息后检查订单状态,如果还未支付就执行取消。

需要特别注意的是,RabbitMQ 对消息 TTL 的处理是在"队列头部检查"而非主动轮询每条消息。 如果队列是多条不同过期时间的消息混合排列,第一条消息 TTL 未到,后面即使有消息已经过期也不会被处理,因为检查只发生在队列头部。所以建议每个延迟时间独立一个队列,保证同一队列中的所有消息具有统一的 TTL,避免过期消息被头部阻塞。

另外,RabbitMQ 3.8 之后也提供了官方的延迟交换机插件 rabbitmq-delayed-message-exchange,本质上类似逻辑,只是内部把 TTL+DLX 的链路封装好了,使用更简洁。但无论哪种实现,底层都是基于"存活时间到期后重新路由"的机制。

第三,项目中的实际应用。

在面试系统里,我们有一个场景:用户请求生成模拟面试,此时大模型服务可能正在高负载中,直接返回失败用户体验很差。用延迟队列做如下处理:

接到生成请求后,先尝试调大模型服务。如果成功,直接返回结果。如果大模型返回"繁忙",把请求消息发到延时队列,设 TTL 30 秒。消费者监听的是延时队列对应的业务处理队列。30 秒后,消费者收到消息,再次尝试调用大模型------如果这次成功,正常生成面试结果;如果仍然失败,记录异常信息到专门的死信队列,人工介入或通知用户稍后重试。

这样的好处是:用户请求不会直接丢失,系统会自动在合理时间窗口内重试,同时对大模型形成一定程度的压力缓冲。

总结一句话:死信队列是消息被拒绝、过期或队列满时的兜底路由机制;延迟队列通过 TTL + DLX 组合把消息在延时队列里"搁"一段时间,到期后自动转为死信并路由到真正的处理队列,适用于订单超时、失败重试等需要异步延时的场景。

碎碎念:后续会更新每天学习的八股和算法 题,开始准备秋招的第32天。努力连续更新100天!以后每天就按,秋招项目【java+agent】,科研,必做项目,算法,八股,锻炼身体来总结。

总结:得多动脑子

1.算法要系统过一遍【灵神】24/27【早上】1h

2.秋招项目,【java】开始实际看业务,1/6;无

【agent】还在学,整理cc,无,

3.科研要跑一下,【下午】3h

4.检测项目也得总结文档,【晚上】5h

6.背八股,无

7.锻炼身体,无

杂活2h

反思:做完东西要总结

相关推荐
骑士雄师1 小时前
19.3 langgraph的工作节点和路由函数
java·前端·数据库
装不满的克莱因瓶1 小时前
RLHF中的PPO算法——大语言模型对齐优化的核心引擎
人工智能·python·深度学习·算法·机器学习·语言模型·自然语言处理
SWAGGY..1 小时前
Linux系统编程:(十三)环境变量
java·linux·算法
程序员黑豆1 小时前
AI全栈开发 - Java:基本数据类型 vs 引用数据类型的内存存储
java·前端·ai编程
Black蜡笔小新2 小时前
自动化AI算法训练服务器DLTM一体化训推平台构建企业专属AI能力中台
人工智能·算法·自动化
sjsjs112 小时前
力扣3558. 给边赋权值的方案数 I
算法·leetcode·职场和发展
布朗克1682 小时前
34 JVM深入理解
java·jvm
hujinyuan201602 小时前
2025年12月中国电子学会青少年机器人技术等级考试试卷(四级) 真题+答案
算法·机器人
啦啦啦啦啦zzzz2 小时前
算法总结(双指针)
c++·算法·双指针