螺旋矩阵
要点:模拟,上下左右变换
java
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int top = 0;
int dibu = matrix.length - 1;
int left = 0;
int right = matrix[0].length - 1;
List<Integer> ans = new ArrayList<>();
while(top <= dibu && left <= right){
for(int i = left ; i <= right; i++){
ans.add(matrix[top][i]);
}
top++;
if(top <= dibu){
for(int i = top; i <= dibu; i++){
//ans.add(matrix[right][i]);注意写法,行列是那个在动
ans.add(matrix[i][right]);
}
right--;
}
if(top <= dibu){
for(int i = right; i >= left; i-- ){
ans.add(matrix[dibu][i]);
}
dibu--;
}
if(left <= right){
for(int i = dibu; i>= top; i--){
ans.add(matrix[i][left]);
}
left++;
}
}
return ans;
}
}
旋转图像
要点:先转置,然后反转
java
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
//第一步转置
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++){//对角线下方的元素
int tmp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = tmp;
}
}
//第二部行反转
for(int[] row : matrix){
for(int j = 0; j < n/2; j++){
int tmep = row[j];
row[j] = row[n-1-j];
row[n-1-j] = tmep;
}
}
}
}
矩阵置零
要点: 模拟
java
class Solution {
public void setZeroes(int[][] matrix) {
int n = matrix.length;
int m = matrix[0].length;
boolean[] hang = new boolean[n];
boolean[] lie = new boolean[m];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(matrix[i][j] == 0){
hang[i] = lie[j] = true;
}else{
continue;
}
}
}
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(hang[i] || lie[j]){
matrix[i][j] = 0;
}
}
}
}
}
随机知识
Q1:happens-before 举例说明 volatile 规则和传递性
你的回答:基本正确但缺少举例。
标准答案(面试官想要的):
"happens-before 是 JMM 的核心,例如 volatile 变量规则 :对一个 volatile 变量的写 happens-before 后续对该变量的读。传递性 :若 A happens-before B,B happens-before C,则 A happens-before C。
举例 :线程1执行
a=1(普通写);flag=true(volatile 写)。线程2执行if(flag)读到 true,则a=1对线程2可见。推导:a=1happens-beforeflag=true(程序次序),flag=truehappens-beforeflag读(volatile 规则),flag读 happens-beforea读(程序次序),传递得a=1happens-beforea读。"
改进点 :一定要把传递性链条说出来,并且提到"普通变量 a 也能被看见"。
Q2:DCL 不加 volatile 的问题,以及不用 volatile 的替代方案
你的回答:"会造线程创建这个对象是对其他线程不可见的,加上指令重排,导致其他线程指向对象失败,加其他关键字" ------ 表述不清。
标准答案:
"不加 volatile 时,
instance = new Singleton()的三步(分配内存、初始化、赋值)可能重排序为 1→3→2。线程A执行到步骤3(赋值)但未初始化,线程B判断instance != null直接返回,使用未初始化的对象导致空指针或属性默认值错误。不用 volatile 的替代方案:
静态内部类 Holder :
private static class Holder { static final Singleton INSTANCE = new Singleton(); },利用类加载的初始化锁保证线程安全。枚举单例 :
enum Singleton { INSTANCE; },最简洁,防反射防序列化。"
改进点:不要只说"加其他关键字",要给出具体替代方案名称。
Q3:复杂任务选择 ReAct 还是 Plan-and-Execute?
你的回答:"plan,因为先计划在执行会更好的结果" ------ 太简略,没有对比分析。
标准答案:
"我选择 Plan-and-Execute。原因:
复杂任务步骤多,ReAct 每步都需调用 LLM,成本高且容易在长序列中偏离目标。
Plan-and-Execute 先做全局规划,可并行执行无依赖步骤(如查机票和查酒店同时进行),效率更高。
规划可被缓存或复审,便于调试。
但 ReAct 在环境动态变化、需要实时反馈的场景更优(如游戏操作)。本题是固定流程的行程规划,Plan-and-Execute 更合适。"
改进点:要展示你权衡过两种模式的优劣,而非简单下结论。
Q4:同一用户并发请求同一 Agent 的状态冲突避免(Redis 乐观锁细节)
你的回答:"前端限制,后端去重,版本号用时间戳" ------ 过于简化,且时间戳在高并发下会重复(同一毫秒),不可靠。
标准答案:
"前端限制按钮防抖是辅助手段,后端必须处理。方案:
请求去重 :使用 Redis 的
SETNX对userId+requestId加短时锁,相同请求直接返回已有结果。乐观锁(版本号) :在 Redis 中存储状态 key =
agent:session:{userId},value 包含plan、currentStep、version(自增整数)。更新时用 Lua 脚本或WATCH+MULTI/EXEC,检查 version 是否匹配,不匹配则重试或拒绝。时间戳不可靠 :同一毫秒内可能重复,必须用原子自增(如
INCR)生成版本号。"
改进点 :版本号必须原子自增,不能用时间戳;要提到 Lua 脚本保证原子性。
Q5:LLM 响应慢时的线程模型和超时控制
你的回答:"用 SSE 流式回复" ------ 答非所问。SSE 是客户端接收方式,不解决服务端线程阻塞。
标准答案:
"LLM 响应 5 秒会导致 Tomcat 线程池被占满。解决方案:
异步化 :使用
CompletableFuture或WebFlux非阻塞 I/O,将 LLM 调用提交到独立线程池,主线程快速返回Future。超时控制 :
future.get(3, TimeUnit.SECONDS)或@Async配合TimeoutTask,超时后取消任务并返回降级结果(如"服务繁忙,稍后重试")。线程隔离 :为 LLM 调用单独配置线程池(如
ThreadPoolTaskExecutor),设置队列和拒绝策略,避免拖垮整个服务。熔断降级:使用 Resilience4j 或 Sentinel,当 LLM 调用失败率超过阈值时直接返回兜底回复。
SSE 流式:适合客户端边生成边展示,但服务端仍需异步处理,不能代替超时控制。"
改进点:要区分"超时控制"和"流式传输",前者是服务端健壮性,后者是交互体验。
碎碎念:后续会更新每天学习的八股和算法 题,开始准备秋招的第36天。努力连续更新100天!以后每天就按,秋招项目【java +agent】,科研,必做项目,算法,八股,锻炼身体来总结。
总结:要掌控好自己的时间
1.算法面试150 【早中晚】1h
2.秋招项目,【java 】开始实际看业务,1/6;无
【agent 】还在学,整理cc ,无,
3.科研要跑一下,
4.检测项目,准备数据集【30min】
6.背八股,【30min】
7.锻炼身体,
今天杂活干了7h
反思:少刷短视频,该休息就休息