<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[zander258的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/zander258</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; zander258]]></copyright><item><title><![CDATA[Feed 缓存不要缓存用户态：用页骨架和条目片段拆开共享数据]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/166602250</link><guid>https://blog.youkuaiyun.com/zander258/article/details/166602250</guid><author>zander258</author><pubDate>Fri, 25 Sep 2026 00:20:34 +0800</pubDate><description><![CDATA[本文详解公开Feed缓存设计：通过分离公共内容（页骨架、条目片段）与用户私有状态（liked/faved），实现高效复用与精准个性化。采用Caffeine+Redis三级缓存，以idsKey为粒度做single-flight防击穿，随机TTL防雪崩。关键原则：用户态状态返回前动态计算，任意片段缺失则整页回源，禁止残页。点赞仅更新计数与受影响页面，不重建整页。当前无分布式锁与故障降级机制，存在演进空间。核心边界：共享缓存仅含公共字段，用户态必须实时重算。]]></description><category></category></item><item><title><![CDATA[LeetCode 438：找到字符串中所有字母异位词——定长窗口 + 欠债种类数]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/166492780</link><guid>https://blog.youkuaiyun.com/zander258/article/details/166492780</guid><author>zander258</author><pubDate>Wed, 23 Sep 2026 21:34:43 +0800</pubDate><description><![CDATA[本文通过分析字符串异位词匹配问题，提出基于“欠债表”与“欠债种类数”的高效解法。核心思想：用频次数组记录窗口对目标串的字符“欠债”，len仅统计未凑齐的字符种类数，避免个数与种类混用。滑动窗口保持固定长度，每轮右移一字符后，若窗口长度达标且len==0，则记录起始位置；随后移除左端字符，仅当其原数量恰好为0时才更新len。该方法正确处理无关字符（如e）和重复字符（如aab），确保不漏不重。时间复杂度O(|s|+|p|)，空间复杂度O(1)（忽略输入复制）。关键点：a[c]==0表示种类刚齐，而非字符是否在p]]></description><category></category></item><item><title><![CDATA[点赞计数为什么要先聚合，再写入固定长度 Redis String]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/166353018</link><guid>https://blog.youkuaiyun.com/zander258/article/details/166353018</guid><author>zander258</author><pubDate>Tue, 22 Sep 2026 11:44:36 +0800</pubDate><description><![CDATA[本文阐述了点赞计数链路中Bitmap、Redis Hash与固定长度SDS三类数据的分工机制，重点分析Kafka消息传递、Redis增量聚合与SDS汇总写入的并发与可靠性边界。核心要点包括：事件需在Redis写入后提交Kafka位点以避免少计；刷写时应扣减而非删除聚合字段以防丢失并发增量；SDS读改写必须通过Lua原子操作防止覆盖；当前实现存在生产端不可靠投递、消费端无幂等、无实体分区键及计数漂移无法自动修复等四重边界。演进方向包括双写原子化、事件幂等、分区有序与周期对账，四项缺一不可。]]></description><category></category></item><item><title><![CDATA[点赞状态是一位，不要把雪花 ID 当成 Bitmap 下标]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/166352804</link><guid>https://blog.youkuaiyun.com/zander258/article/details/166352804</guid><author>zander258</author><pubDate>Tue, 22 Sep 2026 11:41:52 +0800</pubDate><description><![CDATA[本文阐述了点赞行为在Redis Bitmap中的高效存储与查询机制：采用分片策略（CHUNK_SIZE=32768），将雪花ID映射为分片号和位偏移，避免单Key过大导致的内存膨胀；通过单一Key、O(1)的GETBIT/SETBIT实现状态判断与翻转；总赞数优先读取快速结构，仅在异常时锁住重建；强调分片设计平衡大Key风险与命令开销，明确O(1)适用范围，避免夸大性能。]]></description><category></category></item><item><title><![CDATA[LeetCode 3：无重复字符的最长子串——重复后从下一个起点重新扫描]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/166141356</link><guid>https://blog.youkuaiyun.com/zander258/article/details/166141356</guid><author>zander258</author><pubDate>Sun, 20 Sep 2026 21:39:36 +0800</pubDate><description><![CDATA[本文讨论了寻找字符串中不含重复字符的最长子串长度的问题。最初尝试用HashMap记录字符最后出现位置，但存在逻辑缺陷：仅依赖重复字符下标差无法保证中间无重复，且可能遗漏末尾子串。修正思路是：以每个位置为起点，用HashMap统计当前扫描区间字符频次，遇重复则清空并回退起点，重新扫描。每轮更新答案，确保覆盖所有情况。时间复杂度最坏为O(n²)，空间复杂度O(min(n,字符集大小))。关键点在于正确推导r = r - len + 1，并配合for循环自增实现起点切换。通过“abba”“dvdf”等案例验证正确]]></description><category></category></item><item><title><![CDATA[关掉标签再打开，Refresh Token 还在却被强制重新登录]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/165890995</link><guid>https://blog.youkuaiyun.com/zander258/article/details/165890995</guid><author>zander258</author><pubDate>Fri, 18 Sep 2026 22:39:43 +0800</pubDate><description><![CDATA[页面刷新后，因前端直接使用过期AccessToken请求/auth/me导致认证失败，误将仍有效的RefreshToken一并清除，引发强制重新登录。问题根源在于：未在恢复流程中优先用RefreshToken刷新AccessToken，且定时刷新周期（60秒）大于刷新窗口（5秒），导致多数情况下无法及时续期。此外，错误处理未区分401与网络异常，一律清空会话。建议改为：读取本地令牌后，若AccessToken即将过期则先刷新，仅当刷新失败才清除状态；401时尝试刷新，网络错误则保留凭证。当前实现尚未落地此逻]]></description><category></category></item><item><title><![CDATA[登录验证码为什么能改密码]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/165890913</link><guid>https://blog.youkuaiyun.com/zander258/article/details/165890913</guid><author>zander258</author><pubDate>Fri, 18 Sep 2026 22:13:39 +0800</pubDate><description><![CDATA[验证码需按场景与账号隔离存储，Key必须包含scene和identifier，防止跨场景复用。校验成功后须立即删除记录，不可仅依赖TTL。发送侧限流分间隔、日次数、失败次数三类，避免被刷或猜码。当前实现为先读再删，存在并发重放风险，建议使用Lua脚本原子化处理。验证码状态依赖Redis，不可用时应关闭发送与校验。对外返回应模糊化，防止账号枚举。当前方案可演进至原子校验、独立限流策略及更安全的错误提示。]]></description><category></category></item><item><title><![CDATA[LeetCode 15. 三数之和]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/165630784</link><guid>https://blog.youkuaiyun.com/zander258/article/details/165630784</guid><author>zander258</author><pubDate>Wed, 16 Sep 2026 21:44:41 +0800</pubDate><description><![CDATA[本文分析了三数之和问题的正确解法。核心思路是排序后固定第一个数，用双指针在右侧寻找另两个数，通过i&lt;j&lt;k保证下标不同，利用排序实现去重。原思路依赖Set判断值存在，无法保证下标独立，易出错。正确做法在固定i时跳过重复值，找到答案后移动双指针并避免重复加入。时间复杂度O(n²)，空间复杂度O(1)。关键在于明确候选范围与去重层级。]]></description><category></category></item><item><title><![CDATA[知识分享平台项目复习第二天：登录模块中的双令牌与刷新安全（2）]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/165594333</link><guid>https://blog.youkuaiyun.com/zander258/article/details/165594333</guid><author>zander258</author><pubDate>Wed, 16 Sep 2026 10:50:13 +0800</pubDate><description><![CDATA[项目复习第二天聚焦认证安全，梳理了XSS、CSRF与CORS的核心区别：XSS是恶意脚本在目标网站执行，可窃取localStorage中的令牌；CSRF利用浏览器自动携带Cookie，伪造用户请求；CORS仅限制跨源响应读取，不防请求发送。当前项目将令牌存于localStorage，面临XSS风险，虽用HttpOnly降低RefreshToken泄露，但无法阻止脚本冒用权限。结合SpringSecurity链路，明确401为认证失败，403为授权不足，且permitAll()不跳过安全过滤器链。]]></description><category></category></item><item><title><![CDATA[LeetCode 11. 盛最多水的容器]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/165365028</link><guid>https://blog.youkuaiyun.com/zander258/article/details/165365028</guid><author>zander258</author><pubDate>Mon, 14 Sep 2026 23:36:48 +0800</pubDate><description><![CDATA[本文分析了盛最多水容器问题的正确解法。初始错误思路仅维护左侧最高柱子，忽略了“高度较低但距离更远”的组合可能更优。正确方法采用双指针：从两端开始，面积由较短边决定，每次移动较短一侧，因保留短板无法提升高度而宽度减小，故可安全舍弃。该策略确保不遗漏最优解，时间复杂度O(n)，空间复杂度O(1)。]]></description><category></category></item><item><title><![CDATA[知识分享平台项目复习第一天：登录模块中的双令牌与刷新安全]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/165244968</link><guid>https://blog.youkuaiyun.com/zander258/article/details/165244968</guid><author>zander258</author><pubDate>Sun, 13 Sep 2026 23:29:30 +0800</pubDate><description><![CDATA[本文系统梳理了基于JWT的双令牌登录机制，重点解析验证码登录、RefreshToken白名单与轮换、登出空窗期等核心设计。通过Redis仅存储jti实现无状态认证，保障性能与可撤销性；利用Lua脚本原子化处理刷新流程，防止并发重复使用旧令牌；明确区分AccessTokenTTL、RefreshTokenTTL与Rotation的关系，理解滑动会话与绝对期限差异。针对登出后空窗期问题，提出黑名单方案作为即时失效补充。最终强调：登录状态生命周期管理依赖于服务端对刷新请求的正确处理，而非客户端过期触发。]]></description><category></category></item><item><title><![CDATA[LeetCode 49. 字母异位词分组]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164976661</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164976661</guid><author>zander258</author><pubDate>Fri, 11 Sep 2026 11:39:38 +0800</pubDate><description><![CDATA[这道题的关键是为每组字母异位词找到统一标识。将字符排序后得到的字符串可以作为规范化 key，使不同顺序但字符组成相同的字符串进入同一个分组。本次主要问题不是分组思路，而是创建分组时判断错了对象。遇到类似问题时，可以先手动模拟每组的第一个元素，确认新的 key 能否被创建并立即保存当前数据。]]></description><category></category></item><item><title><![CDATA[LeetCode 128. 最长连续序列]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164976573</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164976573</guid><author>zander258</author><pubDate>Fri, 11 Sep 2026 11:39:01 +0800</pubDate><description><![CDATA[这道题的关键不是把相邻数字都数一遍，而是先认出每一段的起点。x-1不在集合中时，从x向后走到断掉，用y - x得到段长，再和全局答案取最大。本次主要问题有两层：一开始把多段长度加在了一起；后来虽然找到了起点，但既没有保留历史最长，也没有从起点把整段扫完。遇到类似「无序集合里找连续段」的问题时，可以先问自己：当前这个数是不是这段的起点？]]></description><category></category></item><item><title><![CDATA[OMP 默认快捷键说明]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164756097</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164756097</guid><author>zander258</author><pubDate>Wed, 09 Sep 2026 20:19:18 +0800</pubDate><description><![CDATA[oh-my-Pi的快捷键说明，叫你如何切换模型的角色]]></description><category></category></item><item><title><![CDATA[LeetCode 5. 最长回文子串]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164726834</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164726834</guid><author>zander258</author><pubDate>Wed, 09 Sep 2026 10:50:52 +0800</pubDate><description><![CDATA[这题的优化关键是利用回文串的中心对称性，将“枚举子串并完整检查”改成“枚举中心并向两边扩展”。实现时需要同时处理奇数、偶数两种中心，并牢记扩展结束后指针已经多走一步，实际长度为。]]></description><category></category></item><item><title><![CDATA[LeetCode 72. 编辑距离]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164628766</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164628766</guid><author>zander258</author><pubDate>Tue, 08 Sep 2026 17:40:16 +0800</pubDate><description><![CDATA[这题的核心不是“怎么操作”，而是“怎么定义状态”。把状态定义成两个前缀的最少编辑次数后，递推就只剩三种选择：删、插、换。记忆化搜索和二维 DP 本质一致，只是写法不同。]]></description><category></category></item><item><title><![CDATA[LeetCode 1143. 最长公共子序列]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164496611</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164496611</guid><author>zander258</author><pubDate>Mon, 07 Sep 2026 20:13:42 +0800</pubDate><description><![CDATA[dp[i][j]：text1 的前 i 个字符和 text2 的前 j 个字符的最长公共子序列长度因为i和jtext1[i - 1] 和 text2[j - 1]这题的关键是把状态定义为两个字符串的前缀，而不是以某个字符结尾的字符串。当当前字符相等时，继承左上角状态并加一；当当前字符不相等时，分别舍弃两个字符串的当前字符，取两条路径中的较大值。]]></description><category></category></item><item><title><![CDATA[LeetCode 64. 最小路径和]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164430984</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164430984</guid><author>zander258</author><pubDate>Sun, 06 Sep 2026 21:43:26 +0800</pubDate><description><![CDATA[dfs(i,j)：从 (0,0) 到达 (i,j) 的最小路径和。这个定义的重点是：返回值已经包含当前位置grid[i][j]。所以起点不是返回0grid[0][0]这题的核心不是换解法，而是让边界返回值服务于min这个转移。dfs(i,j)：到达坐标 (i,j) 的最小路径和那么越界就应该返回“大数”来表示非法路径，起点就应该返回grid[0][0]来计入起点值。用[[1,2]]这种一行网格手推一遍，很容易发现越界返回0会把非法路径选进来。]]></description><category></category></item><item><title><![CDATA[LeetCode 62. 不同路径]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164376366</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164376366</guid><author>zander258</author><pubDate>Fri, 04 Sep 2026 21:57:49 +0800</pubDate><description><![CDATA[dfs(i,j)：从 (0,0) 到达 (i,j) 的不同路径数。ij是坐标下标，不是行数和列数。dfs(i,j)：到达坐标 (i,j) 的路径数这题的核心不是换解法，而是把“网格尺寸”和“坐标下标”区分清楚。dfs(i,j)：到达坐标 (i,j) 的路径数用这种最小用例手推一遍，很容易发现入口是否偏了一格。]]></description><category></category></item><item><title><![CDATA[LeetCode 32. 最长有效括号]]></title><link>https://blog.youkuaiyun.com/zander258/article/details/164341257</link><guid>https://blog.youkuaiyun.com/zander258/article/details/164341257</guid><author>zander258</author><pubDate>Thu, 03 Sep 2026 23:21:34 +0800</pubDate><description><![CDATA[这题的关键是先把“括号是否匹配”和“有效子串是否连续”拆开。当前 ')' 只能匹配最近的、尚未匹配的 '('isValid被标记的位置连续多少个，最长有效括号子串就是多少。这份写法虽然不是最省空间的栈写法，但思路清晰：先标记所有有效位置，再统计最长连续有效区间。]]></description><category></category></item></channel></rss>