From cbe7a30f91e736cccd2fa39ffc1104e37744bb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E8=90=8C=E8=8A=BD?= <3205788256@qq.com> Date: Wed, 24 Jun 2026 21:58:50 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=90=8C=E6=AD=A5=E7=AC=94=E8=AE=B0?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E4=B8=8E=E7=9B=AE=E5=BD=95=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mengyanote/.obsidian/app.json | 3 +- .../data/mengyanote/.obsidian/appearance.json | 2 +- .../plugins/obsidian42-brat/data.json | 2 +- .../.obsidian/themes/Phycat/manifest.json | 2 +- .../.obsidian/themes/Phycat/theme.css | 162 ++++--- .../data/mengyanote/.obsidian/workspace.json | 98 ++-- .../前端开发/前端全局字体样式提示词.md | 1 + .../前端开发/前端构建分离网页版和桌面版.md | 3 + .../前端开发/前端网页做成PWA应用.md | 1 + .../AI/提示词工程/前端开发/前端随机背景图.md | 2 +- .../开发通用提示词/开源项目编写博客介绍文章.md | 5 + .../开发通用提示词/项目完善上传Github.md | 4 + .../AI/提示词工程/角色扮演/模拟算法大师.md | 24 - .../提示词工程/项目初始化模板/CloudFlare Worker项目.md} | 0 .../React和Vite前端+Golang和Gin后端+SQLite储存.md | 0 .../React和Vite前端+Python和Flask后端+SQLite储存.md | 0 .../data/mengyanote/AI/未命名.md | 4 +- ...e KV、D1、R2 三种存储服务的核心差异对比.md | 24 +- .../data/mengyanote/Git/Git提交规范.md | 43 ++ ...ux 如何快速删除一个目录下的一百万个文件.md | 89 ++++ .../mengyanote/MarkDown/树萌芽のGithub主页.md | 64 +-- .../BTC实时官方API接口.md} | 16 +- .../data/mengyanote/Web3区块链/BTC销毁方法.md | 52 ++ .../polymarket预测市场投资方法.md | 0 .../Web3区块链/web3区块链主流公链总结.md | 31 ++ .../Web3区块链/币安BTC实时价格监控API.md | 49 ++ .../data/mengyanote/临时/dex交易所.md | 62 +++ .../mengyanote/临时/golang实现自举历程.md | 80 ++++ .../mengyanote/临时/golang面试八股常识.md | 206 ++++++++ .../临时/usdt,usdc超级管理员后门.md | 31 ++ .../临时/web1,web2,web3以及web4特点与区别.md | 75 +++ .../data/mengyanote/临时/八股/GoFrame框架.md | 252 ++++++++++ .../临时/八股/ReAct和Plan-Execute模式区别.md | 111 +++++ .../mengyanote/临时/八股/Redis底层数据结构.md | 93 ++++ .../data/mengyanote/临时/八股/http状态码.md | 50 ++ .../mengyanote/临时/八股/rag检索增强生成.md | 160 +++++++ .../临时/八股/前后端登录验证方式总结.md | 187 ++++++++ .../八股/栈与堆:概念、区别及内存管理详解.md | 57 +++ .../data/mengyanote/临时/八股/触发跨域类型.md | 13 + .../临时/删除指定网站浏览数据和缓存方法.md | 52 ++ .../data/mengyanote/临时/哈希算法总结.md | 53 ++ ...妙妙工具] MD Editor 一个轻量级markdown编辑器.md | 67 +++ ...] 萌芽表情包图库 —— 一个纯静态的表情包 API + 图库.md | 174 +++++++ ...RandBG API:一个零成本、可自托管的随机背景图片API.md | 98 ++++ .../1000瓶酒,有一瓶是毒药,多少只老鼠可以查出来?.md | 25 + .../实习求职/树萌芽の简历/Golang后端开发.md | 53 ++ .../{简历 => 树萌芽の简历}/Java后端开发.md | 0 .../{简历 => 树萌芽の简历}/运维工程师.md | 0 .../实习求职/简历/Golang后端开发.md | 40 -- .../实习求职/通用面试八股/Agent面试八股.md | 296 +++++++++++- .../字节}/✅27双非本一腾讯IEG游戏安全后台实习面经.md | 0 .../字节}/✅4.13字节一面.md | 0 .../字节}/✅Go后端开发-字节一面.md | 0 .../字节}/✅字节-后端开发面经.md | 0 .../字节}/✅字节Agent中台一面凉经.md | 0 .../字节}/✅字节一面 4.15.md | 0 .../{Golang后端 => Golang后端开发/字节}/✅字节一面.md | 0 .../字节}/✅字节后端2面.md | 0 .../字节}/✅字节后端一面-65min八股拷打全复盘.md | 0 .../字节}/✅字节后端二面.md | 0 .../字节}/✅字节后端实习三面.md | 0 .../字节}/✅某佬面试经历.md | 0 .../字节}/✅某字节一面.md | 0 .../字节}/字节后端开发一面面经.md | 0 .../Java后端开发/{ => 字节}/字节国际支付二面.md | 0 .../{ => 字节}/字节跳动TikTok后端开发日常实习一面面经.md | 0 .../Java后端开发/{ => 字节}/某字节二面面经.md | 0 .../Java后端开发/腾讯/腾讯IEG后台开发日常实习二面.md | 29 ++ .../腾讯/腾讯ieg后端日常实习一二三面面经.md | 34 ++ .../2026.6.18深势科技Golang后端一面.md | 18 + .../树萌芽の面试经历/2026.6.20豆包模拟面试-1.md | 35 ++ .../通用后端开发/6.4 JD YOUNG后端开发一面凉经.md | 12 + .../项目经历/MengyaNoteRAG/mengya-rag项目简介.md | 134 ++++++ .../SproutClaw/SproutClaw的MCP工具应用情况.md | 151 ++++++ .../SproutClaw/SproutClaw的上下文工程详情.md | 452 ++++++++++++++++++ ...tClaw的工作流程是react吗,是否有plan-execute模式.md | 196 ++++++++ .../项目经历/SproutClaw/SproutClaw简介.md | 41 ++ .../前后端交互相对路径和绝对路径区别.md | 60 +++ .../{localsend.md => 项目分析/LocalSend.md} | 0 .../{ => 项目分析}/Rusted Warfare.md | 0 .../数据库/MySQL/MySQL基础语法总结.md | 199 ++++++++ .../数据库/MySQL/MySQL的内置系统数据库.md | 112 +++++ .../数据库/MySQL/Typora_Hook_Log.txt | 198 ++++++++ .../数据库/MySQL/控制台连接MySQL教程.md | 132 +++-- .../mengyanote/数据库/MySQL/有趣的代码片段.md | 5 + .../SQL-Server/SQL-Server常用语法操作.md | 182 +++++++ .../SQL-Server/SQL-Server常见函数分类总结.md | 71 +++ .../SQL-Server/SQL-Server的视图是什么.md | 39 ++ .../SQL-Server/SQL-Server联表查询类型.md | 78 +++ .../data/mengyanote/数据库/SQL定义.md | 28 ++ .../mengyanote/数据库/小萌芽开发中间件信息.md | 71 --- .../账号合集/AI账号/Grok账号.md | 24 + .../账号合集/AI账号/英伟达账号.md | 14 + .../树萌芽の小本本/账号合集/CloudFlare账号.md | 15 +- .../树萌芽の小本本/账号合集/Github账号.md | 25 +- .../树萌芽の小本本/账号合集/Grok账号.md | 4 - .../账号合集/邮箱账号/Gmail邮箱.md | 3 +- .../mengyanote/树萌芽の小本本/重要信息记录.md | 4 + .../生活科普/租房全流程避坑终极指南.md | 129 +++++ .../2025年蓝桥杯PythonB组真题解析/1.攻击次数.md | 26 - .../{1.两数之和.md => (1)1.两数之和.md} | 2 +- .../LeetCode热题100/(10)560. 和为 K 的子数组.md | 180 +++++++ .../LeetCode热题100/(11)239. 滑动窗口最大值.md | 194 ++++++++ .../LeetCode热题100/(12)76. 最小覆盖子串.md | 177 +++++++ .../LeetCode热题100/(13)53. 最大子数组和.md | 217 +++++++++ .../LeetCode热题100/(14)56. 合并区间.md | 154 ++++++ .../LeetCode热题100/(15)189. 轮转数组.md | 223 +++++++++ .../(16)238. 除了自身以外数组的乘积.md | 172 +++++++ .../LeetCode热题100/(17)41. 缺失的第一个正数.md | 220 +++++++++ .../LeetCode热题100/(18)73. 矩阵置零.md | 263 ++++++++++ .../LeetCode热题100/(19)54. 螺旋矩阵.md | 199 ++++++++ .../{49.字母异位词分组.md => (2)49.字母异位词分组.md} | 0 .../LeetCode热题100/(20)48. 旋转图像.md | 221 +++++++++ .../LeetCode热题100/(21)240. 搜索二维矩阵 II.md | 219 +++++++++ .../{128.最长连续序列.md => (3)128.最长连续序列.md} | 2 +- .../LeetCode热题100/(4)283.移动零.md | 140 ++++++ .../LeetCode热题100/(5)11.盛最多水的容器.md | 135 ++++++ .../LeetCode热题100/(6)15.三数之和.md | 163 +++++++ .../LeetCode热题100/(7)42.接雨水.md | 208 ++++++++ .../LeetCode热题100/(8)3.无重复字符的最长子串.md | 153 ++++++ .../(9)438.找出字符串中的所有字母异位词.md | 253 ++++++++++ .../Python数组,元组,集合,字典数据结构对比.md | 68 +++ .../西南石油大学/网络互连ensp常用命令总结.md | 296 ++++++++++++ .../运维/{ => nginx}/nginx快速配置反向代理.md | 0 .../运维/{ => nginx}/nginx模块大全.md | 4 - .../运维/减少运营商对udp的qos限制.md | 4 - ...(自上而下).md => 域名跳转的三种设置(自上而下).md} | 0 .../运维/快速申请https证书并配置自动续期.md | 3 - .../SQL题:查某个班级下所有学生的选课情况.md | 42 ++ ...、课程成绩表,求不存在01课程但存在02课程的学生的成绩.md | 18 + .../如何用 MySQL 实现一个可重入的锁?.md | 12 + ...t_id,score),查询总分排名在5-10名的学生id及对应的总分.md | 26 + 132 files changed, 8974 insertions(+), 431 deletions(-) create mode 100644 mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端构建分离网页版和桌面版.md create mode 100644 mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端网页做成PWA应用.md create mode 100644 mengyanote-backend/data/mengyanote/AI/提示词工程/开发通用提示词/开源项目编写博客介绍文章.md create mode 100644 mengyanote-backend/data/mengyanote/AI/提示词工程/开发通用提示词/项目完善上传Github.md rename mengyanote-backend/data/mengyanote/{博客文章/[萌芽妙妙工具].md => AI/提示词工程/项目初始化模板/CloudFlare Worker项目.md} (100%) create mode 100644 mengyanote-backend/data/mengyanote/AI/提示词工程/项目初始化模板/React和Vite前端+Golang和Gin后端+SQLite储存.md create mode 100644 mengyanote-backend/data/mengyanote/AI/提示词工程/项目初始化模板/React和Vite前端+Python和Flask后端+SQLite储存.md create mode 100644 mengyanote-backend/data/mengyanote/Git/Git提交规范.md create mode 100644 mengyanote-backend/data/mengyanote/Linux/linux 如何快速删除一个目录下的一百万个文件.md rename mengyanote-backend/data/mengyanote/{量化投资/比特币实时官方API接口.md => Web3区块链/BTC实时官方API接口.md} (79%) create mode 100644 mengyanote-backend/data/mengyanote/Web3区块链/BTC销毁方法.md rename mengyanote-backend/data/mengyanote/{量化投资 => Web3区块链}/polymarket预测市场投资方法.md (100%) create mode 100644 mengyanote-backend/data/mengyanote/Web3区块链/web3区块链主流公链总结.md create mode 100644 mengyanote-backend/data/mengyanote/Web3区块链/币安BTC实时价格监控API.md create mode 100644 mengyanote-backend/data/mengyanote/临时/dex交易所.md create mode 100644 mengyanote-backend/data/mengyanote/临时/golang实现自举历程.md create mode 100644 mengyanote-backend/data/mengyanote/临时/golang面试八股常识.md create mode 100644 mengyanote-backend/data/mengyanote/临时/usdt,usdc超级管理员后门.md create mode 100644 mengyanote-backend/data/mengyanote/临时/web1,web2,web3以及web4特点与区别.md create mode 100644 mengyanote-backend/data/mengyanote/临时/八股/GoFrame框架.md create mode 100644 mengyanote-backend/data/mengyanote/临时/八股/ReAct和Plan-Execute模式区别.md create mode 100644 mengyanote-backend/data/mengyanote/临时/八股/Redis底层数据结构.md create mode 100644 mengyanote-backend/data/mengyanote/临时/八股/http状态码.md create mode 100644 mengyanote-backend/data/mengyanote/临时/八股/rag检索增强生成.md create mode 100644 mengyanote-backend/data/mengyanote/临时/八股/前后端登录验证方式总结.md create mode 100644 mengyanote-backend/data/mengyanote/临时/八股/栈与堆:概念、区别及内存管理详解.md create mode 100644 mengyanote-backend/data/mengyanote/临时/八股/触发跨域类型.md create mode 100644 mengyanote-backend/data/mengyanote/临时/删除指定网站浏览数据和缓存方法.md create mode 100644 mengyanote-backend/data/mengyanote/临时/哈希算法总结.md create mode 100644 mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具] MD Editor 一个轻量级markdown编辑器.md create mode 100644 mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具] 萌芽表情包图库 —— 一个纯静态的表情包 API + 图库.md create mode 100644 mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具]RandBG API:一个零成本、可自托管的随机背景图片API.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/场景题,智力题/1000瓶酒,有一瓶是毒药,多少只老鼠可以查出来?.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/树萌芽の简历/Golang后端开发.md rename mengyanote-backend/data/mengyanote/实习求职/{简历 => 树萌芽の简历}/Java后端开发.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/{简历 => 树萌芽の简历}/运维工程师.md (100%) delete mode 100644 mengyanote-backend/data/mengyanote/实习求职/简历/Golang后端开发.md rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅27双非本一腾讯IEG游戏安全后台实习面经.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅4.13字节一面.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅Go后端开发-字节一面.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅字节-后端开发面经.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅字节Agent中台一面凉经.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅字节一面 4.15.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅字节一面.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅字节后端2面.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅字节后端一面-65min八股拷打全复盘.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅字节后端二面.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅字节后端实习三面.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅某佬面试经历.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Golang后端开发/字节}/✅某字节一面.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/{Golang后端 => Java后端开发/字节}/字节后端开发一面面经.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/{ => 字节}/字节国际支付二面.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/{ => 字节}/字节跳动TikTok后端开发日常实习一面面经.md (100%) rename mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/{ => 字节}/某字节二面面经.md (100%) create mode 100644 mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/腾讯/腾讯IEG后台开发日常实习二面.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/腾讯/腾讯ieg后端日常实习一二三面面经.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/面试经历/树萌芽の面试经历/2026.6.18深势科技Golang后端一面.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/面试经历/树萌芽の面试经历/2026.6.20豆包模拟面试-1.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/面试经历/通用后端开发/6.4 JD YOUNG后端开发一面凉经.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/项目经历/MengyaNoteRAG/mengya-rag项目简介.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的MCP工具应用情况.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的上下文工程详情.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的工作流程是react吗,是否有plan-execute模式.md create mode 100644 mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw简介.md create mode 100644 mengyanote-backend/data/mengyanote/技术原理解析/前后端交互相对路径和绝对路径区别.md rename mengyanote-backend/data/mengyanote/技术原理解析/{localsend.md => 项目分析/LocalSend.md} (100%) rename mengyanote-backend/data/mengyanote/技术原理解析/{ => 项目分析}/Rusted Warfare.md (100%) create mode 100644 mengyanote-backend/data/mengyanote/数据库/MySQL/MySQL基础语法总结.md create mode 100644 mengyanote-backend/data/mengyanote/数据库/MySQL/MySQL的内置系统数据库.md create mode 100644 mengyanote-backend/data/mengyanote/数据库/MySQL/Typora_Hook_Log.txt create mode 100644 mengyanote-backend/data/mengyanote/数据库/MySQL/有趣的代码片段.md create mode 100644 mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server常用语法操作.md create mode 100644 mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server常见函数分类总结.md create mode 100644 mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server的视图是什么.md create mode 100644 mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server联表查询类型.md create mode 100644 mengyanote-backend/data/mengyanote/数据库/SQL定义.md create mode 100644 mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/AI账号/英伟达账号.md delete mode 100644 mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/Grok账号.md create mode 100644 mengyanote-backend/data/mengyanote/生活科普/租房全流程避坑终极指南.md delete mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/2025年蓝桥杯PythonB组真题解析/1.攻击次数.md rename mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/{1.两数之和.md => (1)1.两数之和.md} (99%) create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(10)560. 和为 K 的子数组.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(11)239. 滑动窗口最大值.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(12)76. 最小覆盖子串.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(13)53. 最大子数组和.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(14)56. 合并区间.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(15)189. 轮转数组.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(16)238. 除了自身以外数组的乘积.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(17)41. 缺失的第一个正数.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(18)73. 矩阵置零.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(19)54. 螺旋矩阵.md rename mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/{49.字母异位词分组.md => (2)49.字母异位词分组.md} (100%) create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(20)48. 旋转图像.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(21)240. 搜索二维矩阵 II.md rename mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/{128.最长连续序列.md => (3)128.最长连续序列.md} (99%) create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(4)283.移动零.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(5)11.盛最多水的容器.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(6)15.三数之和.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(7)42.接雨水.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(8)3.无重复字符的最长子串.md create mode 100644 mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(9)438.找出字符串中的所有字母异位词.md create mode 100644 mengyanote-backend/data/mengyanote/编程语言/Python/Python数组,元组,集合,字典数据结构对比.md create mode 100644 mengyanote-backend/data/mengyanote/西南石油大学/网络互连ensp常用命令总结.md rename mengyanote-backend/data/mengyanote/运维/{ => nginx}/nginx快速配置反向代理.md (100%) rename mengyanote-backend/data/mengyanote/运维/{ => nginx}/nginx模块大全.md (98%) rename mengyanote-backend/data/mengyanote/运维/{域名的三种设置(自上而下).md => 域名跳转的三种设置(自上而下).md} (100%) create mode 100644 mengyanote-backend/data/mengyanote/面试求职/SQL面试题/SQL题:查某个班级下所有学生的选课情况.md create mode 100644 mengyanote-backend/data/mengyanote/面试求职/SQL面试题/sql题:给学生表、课程成绩表,求不存在01课程但存在02课程的学生的成绩.md create mode 100644 mengyanote-backend/data/mengyanote/面试求职/SQL面试题/如何用 MySQL 实现一个可重入的锁?.md create mode 100644 mengyanote-backend/data/mengyanote/面试求职/SQL面试题/给定一个学生表 student_score(stu_id,subject_id,score),查询总分排名在5-10名的学生id及对应的总分.md diff --git a/mengyanote-backend/data/mengyanote/.obsidian/app.json b/mengyanote-backend/data/mengyanote/.obsidian/app.json index c9b14c3..5263b35 100644 --- a/mengyanote-backend/data/mengyanote/.obsidian/app.json +++ b/mengyanote-backend/data/mengyanote/.obsidian/app.json @@ -10,5 +10,6 @@ "autoPairMarkdown": false, "smartIndentList": false, "useTab": true, - "tabSize": 4 + "tabSize": 4, + "focusNewTab": true } \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/.obsidian/appearance.json b/mengyanote-backend/data/mengyanote/.obsidian/appearance.json index 468f509..7c2035d 100644 --- a/mengyanote-backend/data/mengyanote/.obsidian/appearance.json +++ b/mengyanote-backend/data/mengyanote/.obsidian/appearance.json @@ -3,7 +3,7 @@ "theme": "moonstone", "monospaceFontFamily": "Maple Mono CN,霞鹜文楷", "baseFontSize": 15, - "interfaceFontFamily": "霞鹜文楷", + "interfaceFontFamily": "霞鹜文楷,Maple Mono CN", "textFontFamily": "霞鹜文楷", "nativeMenus": false, "accentColor": "#ffbb00", diff --git a/mengyanote-backend/data/mengyanote/.obsidian/plugins/obsidian42-brat/data.json b/mengyanote-backend/data/mengyanote/.obsidian/plugins/obsidian42-brat/data.json index cab179a..517ecbf 100644 --- a/mengyanote-backend/data/mengyanote/.obsidian/plugins/obsidian42-brat/data.json +++ b/mengyanote-backend/data/mengyanote/.obsidian/plugins/obsidian42-brat/data.json @@ -4,7 +4,7 @@ "themesList": [ { "repo": "sumruler/obsidian-theme-phycat", - "lastUpdate": "38104268" + "lastUpdate": "39638238" } ], "updateAtStartup": true, diff --git a/mengyanote-backend/data/mengyanote/.obsidian/themes/Phycat/manifest.json b/mengyanote-backend/data/mengyanote/.obsidian/themes/Phycat/manifest.json index ed77b5c..a9af98e 100644 --- a/mengyanote-backend/data/mengyanote/.obsidian/themes/Phycat/manifest.json +++ b/mengyanote-backend/data/mengyanote/.obsidian/themes/Phycat/manifest.json @@ -1,6 +1,6 @@ { "name": "Phycat", - "version": "0.2.9", + "version": "0.2.10", "minAppVersion": "1.9.0", "author": "Xujilong", "authorUrl": "https://github.com/sumruler" diff --git a/mengyanote-backend/data/mengyanote/.obsidian/themes/Phycat/theme.css b/mengyanote-backend/data/mengyanote/.obsidian/themes/Phycat/theme.css index 262591c..94aac2c 100644 --- a/mengyanote-backend/data/mengyanote/.obsidian/themes/Phycat/theme.css +++ b/mengyanote-backend/data/mengyanote/.obsidian/themes/Phycat/theme.css @@ -3,25 +3,25 @@ name: 🐱 Phycat theme Info & Help name.zh: 🐱 Phycat 主题帮助信息 id: phycat-info settings: - - + - id: info-intro type: info-text markdown: true description: "### Phycat Theme \n A vibrant, glassmorphism aesthetic theme for Obsidian. \n\n [Github Repository](https://github.com/sumruler/obsidian-theme-phycat) | [Report Issue](https://github.com/sumruler/obsidian-theme-phycat/issues)| [Support](https://www.phycat.cn/donate.html)" description.zh: "### Phycat 主题 \n 一个充满活力、具有玻璃拟态美感的 Obsidian 主题。\n\n [Github 仓库](https://github.com/sumruler/obsidian-theme-phycat) | [反馈问题](https://github.com/sumruler/obsidian-theme-phycat/issues)| [打赏支持](https://www.phycat.cn/donate.html)" - - + - id: info-font-tip type: info-text markdown: true description: "**💡 Font Recommendation:** \n This theme is optimized for [**LXGW WenKai**](https://github.com/lxgw/LxgwWenKai). Please install it for the best experience." description.zh: "**💡 字体建议:** \n 本主题针对 [**霞鹜文楷 (LXGW WenKai)**](https://github.com/lxgw/LxgwWenKai) 进行了优化,建议安装该字体以获得最佳体验。" - - + - id: info-view-tip type: info-text markdown: true description: "**🪟 Pro Tip: Independent Settings View** \n Press `Ctrl+P` and search for `Style Settings: Show style settings view`. This opens the settings in a separate pane instead of a modal, preventing it from blocking your view." description.zh: "**🪟 技巧:独立设置窗口** \n 按下 `Ctrl+P` 呼出命令面板,搜索 `Style Settings: Show style settings view`。这可以单独打开一个设置面板,避免全屏弹窗遮挡你的笔记。" - - + - id: info-hover-tip type: info-text markdown: true @@ -34,7 +34,7 @@ name: 🎨 Phycat color setting name.zh: 🎨 Phycat 配色设置 id: phycat-colors settings: - - + - id: light-color-scheme title: Color Scheme (Light Mode) title.zh: 配色方案(亮色模式) @@ -44,31 +44,31 @@ settings: allowEmpty: false default: theme-light-sakura options: - - + - label: 🌸 Sakura (Pink / Default) value: theme-light-sakura - - + - label: 🌊 Mint (Mint Blue) value: theme-light-mint - - + - label: ☁️ Sky (Clear Blue) value: theme-light-sky - - + - label: 🌲 Forest (Natural Green) value: theme-light-forest - - + - label: 🟣 Mauve (Orchid Purple) value: theme-light-mauve - - + - label: 🌅 Golden Hour (Warm Amber) value: theme-light-golden - - - label: 🍒 Cheery (Vibrant Red) - value: theme-light-cheery - - + - + label: 🍒 Cherry (Vibrant Red) + value: theme-light-cherry + - label: ⚓ Prussian (Deep Blue) value: theme-light-prussian - - + - id: dark-color-scheme title: Color Scheme (Dark Mode) title.zh: 配色方案(暗色模式) @@ -78,13 +78,13 @@ settings: allowEmpty: false default: theme-dark-vampire options: - - + - label: 🧛 Vampire (Dracula / Default) value: theme-dark-vampire - - + - label: 🌌 Abyss (Midnight Blue) value: theme-dark-abyss - - + - label: ☢️ Radiation (Toxic Green) value: theme-dark-radiation */ @@ -95,7 +95,7 @@ name: 🗂️ Phycat card Layout name.zh: 🗂️ Phycat 卡片布局设置 id: phycat-layout settings: - - + - id: layout-style title: Interface Layout title.zh: 界面布局风格 @@ -105,18 +105,26 @@ settings: allowEmpty: false default: layout-default options: - - + - label: 🔲 Default (Flat) value: layout-default - - + - label: 🃏 Cards (Floating) value: layout-cards - - + - id: rainbow-folders title: 启用彩虹文件夹 (Rainbow Folders) description: 启用后,侧边栏文件列表将变为多彩嵌套的玻璃容器风格,并带有动态类型图标。关闭则恢复 Obsidian 默认样式。 type: class-toggle - - + - + id: folder-icons + title: Folder Icons + title.zh: 文件夹图标 + description: Enable custom folder icons in the file explorer. Disable to restore Obsidian default folder icons. + description.zh: 开启侧边栏文件列表中的自定义文件夹图标;关闭后恢复 Obsidian 默认文件夹图标,若使用iconize插件请关闭此开关。 + type: class-toggle + default: true + - id: bg-mix-percent title: 背景色混合比例(Card模式生效) description: 调整背景色中白色的混合程度(数值越大越白,默认为 90)。 @@ -125,7 +133,7 @@ settings: min: 0 max: 100 step: 1 - + */ @@ -139,7 +147,7 @@ name: 📏 Phycat spacing setting name.zh: 📏 Phycat 文章间距设置 id: phycat-spacing settings: - - + - id: file-line-width title: File line width title.zh: 阅读区宽度 @@ -147,38 +155,38 @@ settings: type: variable-number default: 900 format: px - - + - id: letter-spacing title: Letter spacing title.zh: 字间距 type: variable-number default: 1 format: px - - + - id: line-height-customize title: Line height title.zh: 段落行高 type: variable-number default: 2.2 - - + - id: code-line-height title: code Line height title.zh: 代码行高 type: variable-number default: 1.6 - - + - id: blockquote-line-height title: blockquote Line height title.zh: 引用块行高 type: variable-number default: 1.6 - - + - id: table-line-height title: Table Line height title.zh: 表格行高 type: variable-number default: 1.8 - - + - id: p-spacing title: Paragraph spacing (Reading mode) title.zh: 段落间距(阅读模式) @@ -191,7 +199,7 @@ name: 📑 Phycat heading setting name.ZH: 📑 Phycat 标题设置 id: phycat-headings settings: - - + - id: headings-color-setting title: Headings Colors title.zh: 标题文字颜色设置 @@ -199,14 +207,14 @@ settings: level: 3 collapsed: true - - + - id: h1-light-color title: H1 light color title.zh: H1 亮颜色 type: variable-color format: hex default: '#000000' - - + - id: h1-dark-color title: H1 dark color title.zh: H1 暗颜色 @@ -214,29 +222,29 @@ settings: format: hex default: '#ffffff' - - + - id: h2-light-color title: H2 light color title.zh: H2 亮颜色 type: variable-color format: hex default: '#000000' - - + - id: h2-dark-color title: H2 dark color title.zh: H2 暗颜色 type: variable-color format: hex default: '#ffffff' - - - + + - id: h3-light-color title: H3 light color title.zh: H3 亮颜色 type: variable-color format: hex default: '#000000' - - + - id: h3-dark-color title: H3 dark color title.zh: H3 暗颜色 @@ -244,14 +252,14 @@ settings: format: hex default: '#ffffff' - - + - id: h4-light-color title: H4 light color title.zh: H4 亮颜色 type: variable-color format: hex default: '#000000' - - + - id: h4-dark-color title: H4 dark color title.zh: H4 暗颜色 @@ -259,14 +267,14 @@ settings: format: hex default: '#ffffff' - - + - id: h5-light-color title: H5 light color title.zh: H5 亮颜色 type: variable-color format: hex default: '#000000' - - + - id: h5-dark-color title: H5 dark color title.zh: H5 暗颜色 @@ -274,28 +282,28 @@ settings: format: hex default: '#ffffff' - - + - id: h6-light-color title: H6 light color title.zh: H6 亮颜色 type: variable-color format: hex default: '#000000' - - + - id: h6-dark-color title: H6 dark color title.zh: H6 暗颜色 type: variable-color format: hex default: '#ffffff' - - + - id: heading1-setting title: H1 title title.zh: 一级标题 type: heading level: 3 collapsed: true - - + - id: h1-alignment title: H1 Alignment title.zh: H1 对齐方式 @@ -309,21 +317,21 @@ settings: value: h1-align-center - label: ⬅️ Left value: h1-align-left - - + - id: h1-size title: H1 font size title.zh: H1字体大小 type: variable-number default: 1.618 format: em - - + - id: heading2-setting title: H2 title title.zh: 二级标题 type: heading level: 3 collapsed: true - - + - id: h2-style-select title: Select Style title.zh: 亮色模式风格 @@ -333,13 +341,13 @@ settings: allowEmpty: false default: h2-style-twin options: - - + - label: 🏛️ Twin Pillars (New) value: h2-style-twin - - + - label: 💊 Capsule (Original) value: h2-style-capsule - - + - id: h2-style-dark-select title: Select Style title.zh: 暗色模式选择风格 @@ -349,136 +357,134 @@ settings: allowEmpty: false default: h2-style-dark-twin options: - - + - label: 🏙️ Neon Twin (New) value: h2-style-dark-twin - - + - label: 🔮 Glass Capsule (Original) value: h2-style-dark-capsule - - + - id: h2-size title: H2 font size title.zh: H2字体大小 type: variable-number default: 1.462 format: em - - + - id: h2-spacing-scale-start title: H2 spacing start title.zh: H2前间距 type: variable-number default: 1.318 - - + - id: h2-spacing-scale-end title: H2 spacing end title.zh: H2后间距 type: variable-number default: 1.318 - - + - id: heading3-setting title: H3 title title.zh: 三级标题 type: heading level: 3 collapsed: true - - + - id: h3-size title: H3 font size title.zh: H3字体大小 type: variable-number default: 1.318 format: em - - + - id: h3-spacing-scale-start title: H3 spacing start title.zh: H3前间距 type: variable-number default: 1.5 - - + - id: h3-spacing-scale-end title: H3 spacing end title.zh: H3后间距 type: variable-number default: 1.5 - - + - id: heading4-setting title: H4 title title.zh: 四级标题 type: heading level: 3 collapsed: true - - + - id: h4-size title: H4 font size title.zh: H4字体大小 type: variable-number default: 1.2 format: em - - + - id: h4-spacing-scale-start title: H4 spacing start title.zh: H4前间距 type: variable-number default: 1.5 - - + - id: h4-spacing-scale-end title: H4 spacing end title.zh: H4后间距 type: variable-number default: 1.5 - - + - id: heading5-setting title: H5 title title.zh: 五级标题 type: heading level: 3 collapsed: true - - + - id: h5-size title: H5 font size title.zh: H5字体大小 type: variable-number default: 1.2 format: em - - + - id: h5-spacing-scale-start title: H5 spacing start title.zh: H5前间距 type: variable-number default: 1.5 - - + - id: h5-spacing-scale-end title: H5 spacing end title.zh: H5后间距 type: variable-number default: 1.5 - - + - id: heading6-setting title: H6 title title.zh: 六级标题 type: heading level: 3 collapsed: true - - + - id: h6-size title: H6 font size title.zh: H6字体大小 type: variable-number default: 1.2 format: em - - + - id: h6-spacing-scale-start title: H6 spacing start title.zh: H6前间距 type: variable-number default: 1.5 - - + - id: h6-spacing-scale-end title: H6 spacing end title.zh: H6后间距 type: variable-number default: 1.5 */ - - -:root{--h3-icon-shape:url("data:image/svg+xml;utf8,");--h4-icon-shape:url("data:image/svg+xml;utf8,");--h5-icon-shape:url("data:image/svg+xml;utf8,");--h6-icon-shape:url("data:image/svg+xml;utf8,");--list-spacing:0.075em}body{--blockquote-line-height:1.6;--table-line-height:1.8;--letter-spacing:1px;--code-size:0.95rem;--code-white-space:pre;--code-radius:8px;--checkbox-size:1.25rem;--checkmark-color:#ffffff;--table-border-radius:8px;--text-faint:color-mix(in srgb, var(--primary-color), transparent 20%);--link-external-decoration-hover:none;--titlebar-background:transparent;--titlebar-background-focused:transparent;--he-title-bar-inactive-pinned-bg:color-mix(in srgb, var(--primary-color), #fff 20%);--h1-line-height:1.2;--h2-line-height:1.5;--h3-line-height:1.5;--h4-line-height:1.4;--h5-line-height:1.4;--h6-line-height:1.4;--file-line-width:900px;--h1-spacing-scale-start:1.5;--h1-spacing-scale-end:1.5;--h2-spacing-scale-start:1.5;--h2-spacing-scale-end:1.5;--h3-spacing-scale-start:1.5;--h3-spacing-scale-end:1.5;--h4-spacing-scale-start:1.5;--h4-spacing-scale-end:1.5;--h5-spacing-scale-start:1.5;--h5-spacing-scale-end:1.5;--h6-spacing-scale-start:1.5;--h6-spacing-scale-end:1.5;--heading-spacing:0.5rem;--h3-spacing-scale:1.6;--h2-spacing-scale:0.2;--word-spacing:2px;--h1-letter-spacing:-0.015em;--h2-letter-spacing:-0.011em;--h3-letter-spacing:-0.008em;--h4-letter-spacing:-0.005em;--h5-letter-spacing:-0.002em;--h6-letter-spacing:0em;--h1-line-height:1.2;--h2-line-height:1.2;--h3-line-height:1.3;--h4-line-height:1.4;--h5-line-height:1.4;--h6-line-height:1.4;--h1-size:1.618em;--h2-size:1.462em;--h3-size:1.318em;--h4-size:1.2em;--h5-size:1.2em;--h6-size:1.2em;.token.keyword, .token.tag, .token.selector{color:var(--code-keyword);font-weight:bold}.token.function, .token.class-name{color:var(--code-function)}.token.string, .token.attr-value{color:var(--code-string)}.token.comment{color:var(--code-comment);font-style:italic}.token.number, .token.boolean{color:var(--code-value)}.token.operator, .token.variable{color:var(--code-operator)}.token.property, .token.attr-name{color:var(--code-property)}.token.punctuation{color:var(--code-punctuation)}.token.important, .token.bold{font-weight:bold;color:var(--code-important, var(--code-keyword))}.token.italic{font-style:italic}.token.url{color:var(--code-string);text-decoration:underline}}body.theme-dark.theme-dark-vampire,body.theme-dark:not(.theme-dark-abyss):not(.theme-dark-radiation){--bg-color:#282a36;--text-color:#f8f8f2;--text-color-secondary:#d0d0d0;--border-color:#44475a;--primary-color:#ff5555;--secondary-color:#bd93f9;--accent-color:#8be9fd;--glow-color:rgba(255, 85, 85, 0.6);--hover-background-color:rgb(255, 85, 85);--select-text-bg-color:rgba(255, 16, 16, 0.466);--link-hover-color:#ff92d0;--h1-underline-color:var(--primary-color);--h2-bg-image:radial-gradient(ellipse at center bottom, rgba(255, 85, 85, 0.15), transparent 70%);--h2-bg-image-hover:radial-gradient(ellipse at center bottom, rgba(255, 85, 85, 0.25), transparent 60%);--code-block-bg:#282a36;--code-keyword:#ff79c6;--code-function:#50fa7b;--code-string:#f1fa8c;--code-comment:#6272a4;--code-property:#66d9ef;--code-value:#bd93f9;--code-punctuation:#f8f8f2;--code-tag:#ff79c6;--code-operator:#ff79c6;--code-important:#ff79c6}body.theme-dark.theme-dark-abyss{--bg-color:#0f111a;--text-color:#d6deeb;--text-color-secondary:#7e8c9f;--border-color:#1f2233;--primary-color:#00b7c0;--secondary-color:#2e8bd6;--accent-color:#d500f9;--glow-color:rgba(0, 243, 255, 0.5);--hover-background-color:#00f3ff;--select-text-bg-color:rgba(7, 243, 255, 0.445);--link-hover-color:#82aaff;--h1-underline-color:var(--primary-color);--h2-bg-image:radial-gradient(ellipse at center bottom, rgba(0, 243, 255, 0.15), transparent 70%);--h2-bg-image-hover:radial-gradient(ellipse at center bottom, rgba(0, 243, 255, 0.25), transparent 60%);--code-block-bg:#0f111a;--code-keyword:#c792ea;--code-function:#82aaff;--code-string:#ecc48d;--code-comment:#637777;--code-property:#80cbc4;--code-value:#f78c6c;--code-punctuation:#d6deeb;--code-tag:#ff5370;--code-operator:#89ddff;--code-important:#c792ea}body.theme-dark.theme-dark-radiation{--bg-color:#1b1d1b;--text-color:#e6e6e6;--text-color-secondary:#99a699;--border-color:#333933;--primary-color:#4cd964;--secondary-color:#ffc107;--accent-color:#29b6f6;--glow-color:rgba(76, 217, 100, 0.4);--hover-background-color:#4cd964;--select-text-bg-color:rgba(76, 217, 100, 0.3);--link-hover-color:#a5d6a7;--h1-underline-color:var(--primary-color);--h2-bg-image:radial-gradient(ellipse at center bottom, rgba(76, 217, 100, 0.1), transparent 70%);--h2-bg-image-hover:radial-gradient(ellipse at center bottom, rgba(76, 217, 100, 0.2), transparent 60%);--code-block-bg:#1b1d1b;--code-keyword:#ffcb6b;--code-function:#4cd964;--code-string:#c3e88d;--code-comment:#546e7a;--code-property:#4cd964;--code-value:#f78c6c;--code-punctuation:#e6e6e6;--code-tag:#ff5370;--code-operator:#89ddff;--code-important:#ffcb6b}body.theme-light.theme-light-sakura,body.theme-light:not(.theme-light-sky):not(.theme-light-forest):not(.theme-light-mint):not(.theme-light-mauve):not(.theme-light-golden):not(.theme-light-cheery):not(.theme-light-prussian){--primary-color:#ff7096;--secondary-color:#bd93f9;--bg-color:#fff7fa;--light-deep:#e91e63;--light-light:#ffb7cd;--light-lighter:#ffe3ec;--light-pale:#fff0f5;--text-color:#1c1719;--text-color-secondary:#3f3a3b;--link-hover-color:#d81b60;--select-text-bg-color:rgba(255, 112, 150, 0.3);--glow-color:rgba(255, 112, 150, 0.5);--border-color:color-mix(in srgb, var(--primary-color), transparent 60%);--h2-bg-gradient:linear-gradient(to right, var(--light-light), var(--primary-color), var(--light-light));--h2-shadow-color:rgba(61, 184, 211, 0.15);--h2-shadow-hover:rgba(61, 184, 211, 0.35);--text-bold:var(--light-deep);--code-normal:#546e7a;--code-string:#2e7d32;--code-comment:#b0bec5;--code-keyword:#d81b60;--code-function:#8e24aa;--code-value:#f57c00;--code-tag:#d81b60;--code-operator:#8e24aa;--code-property:#00897b;--code-punctuation:#78909c;--code-block-bg:#fff4f8;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 92%)}body.theme-light.theme-light-sky{--primary-color:#3498db;--secondary-color:#5296d5;--bg-color:#f4faff;--light-deep:#1a5276;--light-light:#85c1e9;--light-lighter:#aed6f1;--light-pale:#ebf5fb;--text-color:#080d12;--text-color-secondary:#0a1112;--link-hover-color:#2980b9;--select-text-bg-color:rgba(52, 152, 219, 0.25);--glow-color:rgba(52, 152, 219, 0.5);--code-block-bg:var(--light-pale);--border-color:color-mix(in srgb, var(--primary-color), transparent 60%);--h2-bg-gradient:linear-gradient(to right, var(--light-light), var(--primary-color), var(--light-light));--h2-shadow-color:rgba(52, 152, 219, 0.15);--h2-shadow-hover:rgba(52, 152, 219, 0.35);--text-bold:var(--light-deep);--code-normal:#24292e;--code-keyword:#d73a49;--code-function:#6f42c1;--code-string:#032f62;--code-value:#005cc5;--code-comment:#6a737d;--code-tag:#22863a;--code-operator:#d73a49;--code-property:#005cc5;--code-punctuation:#24292e;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-forest{--primary-color:#11aa63;--secondary-color:#14ae9c;--bg-color:#f2f9f5;--light-deep:#008145;--light-light:#43bd84;--light-lighter:#68eaad;--light-pale:#f9fffb;--text-color:#000000;--text-color-secondary:#5c7066;--link-hover-color:#009a52;--select-text-bg-color:rgba(17, 170, 99, 0.25);--glow-color:rgba(17, 170, 99, 0.5);--code-block-bg:var(--light-pale);--border-color:color-mix(in srgb, var(--primary-color), transparent 60%);--h2-bg-gradient:linear-gradient(to right, var(--light-light), var(--light-lighter), var(--light-light));--h2-shadow-color:rgba(17, 170, 99, 0.15);--h2-shadow-hover:rgba(17, 170, 99, 0.35);--text-bold:var(--light-deep);--code-normal:#383a42;--code-keyword:#a626a4;--code-function:#4078f2;--code-string:#50a14f;--code-value:#986801;--code-comment:#9ca0a4;--code-tag:#e45649;--code-operator:#0184bc;--code-property:#4078f2;--code-punctuation:#383a42;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-forest h2{text-shadow:0 1px 2px rgba(0, 0, 0, 0.1)}body.theme-light.theme-light-mint{--primary-color:#3db8bf;--secondary-color:#2acd9e;--bg-color:#f4fdff;--light-deep:#089ba3;--light-light:#7aeaf0;--light-lighter:#b2ebf2;--light-pale:#e0f7fa;--text-color:#263238;--text-color-secondary:#546e7a;--link-hover-color:#00838f;--select-text-bg-color:#7aeaf077;--glow-color:rgba(61, 184, 191, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #80F7C4, #3DB8D3, #80F7C4);--h2-shadow-color:rgba(61, 184, 191, 0.15);--h2-shadow-hover:rgba(61, 184, 191, 0.35);--text-bold:var(--light-deep);--code-normal:#37474f;--code-string:#00695c;--code-comment:#90a4ae;--code-keyword:#0097a7;--code-function:#0277bd;--code-value:#f57f17;--code-tag:#0097a7;--code-operator:#0277bd;--code-property:#00695c;--code-punctuation:#546e7a;--code-block-bg:#f0fcff;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-mauve{--primary-color:#A06EB4;--secondary-color:#6A3F7A;--bg-color:#FAFAFC;--light-deep:#6A3F7A;--light-light:#D4B6E0;--light-lighter:#F3E5F5;--light-pale:#F3E5F5;--text-color:#4A235A;--text-color-secondary:#6A3F7A;--link-hover-color:#ba68c8;--select-text-bg-color:#f0d7f966;--glow-color:rgba(160, 110, 180, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #D8B4E2, #A06EB4, #D8B4E2);--h2-shadow-color:rgba(160, 110, 180, 0.15);--h2-shadow-hover:rgba(160, 110, 180, 0.35);--text-bold:var(--light-deep);--code-background:#F2EFF9;--code-normal:#5E35B1;--code-normal:#4a148c;--code-string:#2e7d32;--code-comment:#9fa8da;--code-keyword:#ba68c8;--code-function:#7b1fa2;--code-value:#f57c00;--code-tag:#ba68c8;--code-operator:#7b1fa2;--code-punctuation:#6a1b9a;--code-block-bg:#fcfbfd;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-golden{--primary-color:#f59e0b;--secondary-color:#b45309;--bg-color:#fffbeb;--light-deep:#b45309;--light-light:#fbbf24;--light-lighter:#fef3c7;--light-pale:#fffbeb;--text-color:#78350f;--text-color-secondary:#92400e;--link-hover-color:#f59e0b;--select-text-bg-color:#f59e0b33;--glow-color:rgba(245, 158, 11, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #fcd34d, #f59e0b, #fcd34d);--h2-shadow-color:rgba(245, 158, 11, 0.15);--h2-shadow-hover:rgba(245, 158, 11, 0.35);--text-bold:var(--light-deep);--code-background:#fff7ed;--code-normal:#92400e;--code-normal:#5d4037;--code-string:#689f38;--code-comment:#a1887f;--code-keyword:#d84315;--code-function:#f57f17;--code-value:#e65100;--code-tag:#d84315;--code-operator:#f57f17;--code-punctuation:#8d6e63;--code-block-bg:#fffbf0;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-cheery{--primary-color:#aa1141;--secondary-color:#810000;--bg-color:#fffbfb;--light-deep:#9a0036;--light-light:#ffa6a6;--light-lighter:#fec2c2;--light-pale:#fffbfb;--text-color:#333333;--text-color-secondary:#870e0e;--link-hover-color:#d81b60;--select-text-bg-color:rgba(123, 123, 123, 0.507);--glow-color:rgba(170, 17, 65, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #b41919, #ea68b6, #b41919);--h2-shadow-color:rgba(170, 17, 65, 0.15);--h2-shadow-hover:rgba(170, 17, 65, 0.35);--text-bold:var(--light-deep);--code-background:rgb(177 108 108 / 2%);--code-normal:#9a0000;--code-normal:#4a0d18;--code-string:#2e7d32;--code-comment:#8d6e63;--code-keyword:#c2185b;--code-function:#d32f2f;--code-value:#e65100;--code-tag:#c2185b;--code-operator:#d32f2f;--code-punctuation:#870e0e;--code-block-bg:#fff5f7;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-prussian{--primary-color:#1D4E89;--secondary-color:#003153;--bg-color:#F0F6FA;--light-deep:#003153;--light-light:#6BA3CC;--light-lighter:#E1EDF5;--light-pale:#F0F6FA;--text-color:#003153;--text-color-secondary:#1D4E89;--link-hover-color:#2962ff;--select-text-bg-color:rgba(29, 78, 137, 0.2);--glow-color:rgba(29, 78, 137, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #6BA3CC, #1D4E89, #6BA3CC);--h2-shadow-color:rgba(29, 78, 137, 0.15);--h2-shadow-hover:rgba(29, 78, 137, 0.35);--text-bold:var(--light-deep);--code-background:#EBF5FA;--code-normal:#0F3057;--code-normal:#37474f;--code-string:#2e7d32;--code-comment:#90a4ae;--code-keyword:#0277bd;--code-function:#006064;--code-value:#e65100;--code-tag:#0277bd;--code-operator:#006064;--code-punctuation:#455a64;--code-block-bg:#f5f9fc;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light{--glow-shadow-text:0 0 5px var(--glow-color);--glow-shadow-box:0 0 5px var(--glow-color);--background-primary:color-mix(in srgb, var(--bg-color), #fff 2%);--background-card:color-mix(in srgb, var(--primary-color), #FFF calc(var(--bg-mix-percent) * 1%));--background-primary-alt:color-mix(in srgb, var(--bg-color), #000 3%);--background-secondary:color-mix(in srgb, var(--bg-color), #fff 5%);--background-secondary-alt:color-mix(in srgb, var(--bg-color), #000 8%);--text-normal:var(--text-color);--text-muted:var(--text-color-secondary);--mermaid-text-color:var(--text-color);--text-accent:var(--primary-color);--text-accent-hover:var(--link-hover-color);--list-marker-color:var(--primary-color);--interactive-accent:var(--primary-color);--interactive-accent-hover:var(--link-hover-color);--text-selection:#dce3e9b6;--background-modifier-hover:rgba(0, 0, 0, 0.05);--background-modifier-active-hover:rgba(0, 0, 0, 0.1);--background-modifier-border:var(--border-color);--background-modifier-border-hover:var(--secondary-color);--background-modifier-error:#d32f2f;--background-modifier-success:#388e3c;--code-background:var(--code-block-bg);--code-normal:var(--text-color);--input-shadow:inset 0 0 0 1px var(--border-color);--input-shadow-hover:inset 0 0 0 1px var(--secondary-color);--checkbox-bg-unchecked:color-mix(in srgb, var(--primary-color), transparent 90%);--checkbox-border-unchecked:color-mix(in srgb, var(--primary-color), transparent 50%);--checkbox-bg-checked:var(--primary-color);--checkbox-shadow-checked:0 2px 5px color-mix(in srgb, var(--primary-color), transparent 60%);--table-bg:rgba(255, 255, 255, 0.4);--table-border-inner:rgba(0, 0, 0, 0.06);--table-row-hover-bg:rgba(0, 0, 0, 0.03);--table-th-bg:color-mix(in srgb, var(--primary-color), white 90%);--table-th-border:color-mix(in srgb, var(--primary-color), transparent 80%);--table-cell-hover-bg:color-mix(in srgb, var(--primary-color), white 80%);--table-cell-hover-text:var(--primary-color);--border-color:color-mix(in srgb, var(--primary-color), transparent 50%);--blockquote-background-color:color-mix(in srgb, var(--primary-color), white 96%);--setting-items-background:color-mix(in srgb, var(--light-lighter), transparent 94%);--indentation-guide-color:color-mix(in srgb, var(--primary-color), white 50%);--tag-background:color-mix(in srgb, var(--primary-color), white 85%);--tag-background-hover:color-mix(in srgb, var(--primary-color), white 75%);--tag-border-color:color-mix(in srgb, var(--primary-color), white 50%);--tag-border-color-hover:var(--primary-color);--h1-color:var(--h1-light-color, #000000);--h2-color:var(--h2-light-color, #000000);--h3-color:var(--h3-light-color, #000000);--h4-color:var(--h4-light-color, #000000);--h5-color:var(--h5-light-color, #000000);--h6-color:var(--h6-light-color, #000000)}body.theme-dark{--glow-shadow-text:0 0 8px var(--glow-color);--glow-shadow-box:0 0 8px var(--glow-color);--background-primary:var(--bg-color);--background-primary-alt:var(--bg-color);--background-secondary:color-mix(in srgb, var(--bg-color), #000 15%);--background-secondary-alt:color-mix(in srgb, var(--bg-color), #000 25%);--text-normal:var(--text-color);--text-muted:var(--text-color-secondary);--mermaid-text-color:#000;--text-accent:var(--primary-color);--text-accent-hover:var(--link-hover-color);--list-marker-color:var(--primary-color);--interactive-accent:var(--primary-color);--interactive-accent-hover:var(--link-hover-color);--text-selection:var(--select-text-bg-color);--background-modifier-hover:rgba(255, 255, 255, 0.05);--background-modifier-active-hover:rgba(255, 255, 255, 0.1);--background-modifier-border:var(--border-color);--background-modifier-border-hover:var(--secondary-color);--background-modifier-error:#ff5555;--background-modifier-success:#50fa7b;--code-background:var(--code-block-bg);--code-normal:var(--text-color);--checkbox-bg-unchecked:rgba(255, 255, 255, 0.05);--checkbox-border-unchecked:rgba(255, 255, 255, 0.3);--checkbox-bg-checked:color-mix(in srgb, var(--primary-color), transparent 80%);--checkbox-shadow-checked:0 0 8px var(--primary-color);--table-bg:rgba(255, 255, 255, 0.02);--table-border-inner:rgba(255, 255, 255, 0.05);--table-row-hover-bg:rgba(255, 255, 255, 0.03);--table-th-bg:color-mix(in srgb, var(--primary-color), transparent 95%);--table-th-border:color-mix(in srgb, var(--primary-color), transparent 85%);--table-cell-hover-bg:color-mix(in srgb, var(--primary-color), transparent 85%);--table-cell-hover-text:#fff;--setting-items-background:color-mix(in srgb, var(--primary-color), transparent 96%);--tag-background:color-mix(in srgb, var(--primary-color), transparent 85%);--tag-background-hover:color-mix(in srgb, var(--primary-color), transparent 75%);--tag-border-color:color-mix(in srgb, var(--primary-color), transparent 50%);--tag-border-color-hover:var(--primary-color);--h1-color:var(--h1-dark-color, #ffffff);--h2-color:var(--h2-dark-color, #ffffff);--h3-color:var(--h3-dark-color, #ffffff);--h4-color:var(--h4-dark-color, #ffffff);--h5-color:var(--h5-dark-color, #ffffff);--h6-color:var(--h6-dark-color, #ffffff)}body{--line-height-normal:2.2;--line-height-tight:1.3;--line-height-customize:var(--line-height-normal)}.markdown-preview-view,.markdown-source-view{letter-spacing:var(--letter-spacing);position:relative}.markdown-preview-view p,.markdown-preview-view li{color:var(--text-color-secondary);word-spacing:var(--word-spacing)}.markdown-preview-view,.markdown-source-view.mod-cm6 .cm-scroller{line-height:var(--line-height-customize)}body .markdown-preview-view h1,body .markdown-source-view.mod-cm6 .HyperMD-header-1{color:var(--h1-color) !important}body .markdown-preview-view h2,body .markdown-source-view.mod-cm6 .HyperMD-header-2{color:var(--h2-color) !important}body .markdown-preview-view h3,body .markdown-source-view.mod-cm6 .HyperMD-header-3{color:var(--h3-color) !important}body .markdown-preview-view h4,body .markdown-source-view.mod-cm6 .HyperMD-header-4{color:var(--h4-color) !important}body .markdown-preview-view h5,body .markdown-source-view.mod-cm6 .HyperMD-header-5{color:var(--h5-color) !important}body .markdown-preview-view h6,body .markdown-source-view.mod-cm6 .HyperMD-header-6{color:var(--h6-color) !important}.markdown-preview-view h1,.markdown-preview-view h2,.markdown-preview-view h3,.markdown-preview-view h4,.markdown-preview-view h5,.markdown-preview-view h6,.markdown-source-view.mod-cm6 .HyperMD-header{color:var(--text-color);font-weight:bold;position:relative;transition:all 0.3s ease;margin-block-start:var(--heading-spacing);margin-block-end:var(--heading-spacing)}.markdown-preview-view h1{margin-block-start:calc(var(--heading-spacing)*var(--h1-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h1-spacing-scale-end))}.markdown-preview-view h2{margin-block-start:calc(var(--heading-spacing)*var(--h2-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h2-spacing-scale-end))}.markdown-preview-view h3{margin-block-start:calc(var(--heading-spacing)*var(--h3-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h3-spacing-scale-end))}.markdown-preview-view h4{margin-block-start:calc(var(--heading-spacing)*var(--h4-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h4-spacing-scale-end))}.markdown-preview-view h5{margin-block-start:calc(var(--heading-spacing)*var(--h5-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h5-spacing-scale-end))}.markdown-preview-view h6{margin-block-start:calc(var(--heading-spacing)*var(--h6-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h6-spacing-scale-end))}.markdown-source-view.mod-cm6 .HyperMD-header-1{padding-top:calc(var(--heading-spacing)*var(--h1-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h1-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-2{padding-top:calc(var(--heading-spacing)*var(--h2-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h2-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-3{padding-top:calc(var(--heading-spacing)*var(--h3-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h3-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-4{padding-top:calc(var(--heading-spacing)*var(--h4-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h4-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-5{padding-top:calc(var(--heading-spacing)*var(--h5-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h5-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-6{padding-top:calc(var(--heading-spacing)*var(--h6-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h6-spacing-scale-end) - 0.25rem)}.theme-light .markdown-preview-view .heading-collapse-indicator{margin-inline-start:-47px !important}.theme-dark .markdown-preview-view .heading-collapse-indicator{margin-inline-start:-26px !important}.theme-light .markdown-preview-view h2 .heading-collapse-indicator{margin-inline-start:-19px !important}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2 .heading-collapse-indicator{margin-inline-start:-19px !important}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2 .heading-collapse-indicator{margin-inline-start:-48px !important}.theme-dark .markdown-preview-view h3 .heading-collapse-indicator,.theme-light .markdown-preview-view h3 .heading-collapse-indicator{margin-inline-start:-43px !important}.theme-dark.h1-align-left .markdown-preview-view h1 .heading-collapse-indicator,.theme-light.h1-align-left .markdown-preview-view h1 .heading-collapse-indicator{margin-inline-start:-50px !important}.markdown-source-view.mod-cm6 .cm-fold-indicator .collapse-indicator{inset-inline-end:22px}.h1-align-left .markdown-source-view.mod-cm6 .cm-fold-indicator .collapse-indicator{inset-inline-end:32px}.theme-light.h2-style-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .collapse-indicator,.theme-dark.h2-style-dark-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .collapse-indicator{inset-inline-end:-2px}.theme-light.h2-style-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .collapse-indicator svg,.theme-dark.h2-style-dark-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .collapse-indicator svg,.theme-light.h2-style-capsule .markdown-preview-view h2 .heading-collapse-indicator svg,.theme-dark.h2-style-dark-capsule .markdown-preview-view h2 .heading-collapse-indicator svg{color:#eee}.theme-light .markdown-preview-view h1,.theme-light .markdown-source-view.mod-cm6 .HyperMD-header-1{font-weight:700;line-height:1.4;padding-bottom:12px;display:table;width:auto;min-width:120px;text-align:center;margin-left:auto !important;margin-right:auto !important;position:relative;transition:color 0.3s ease, transform 0.3s ease}.theme-light .markdown-preview-view h1::after,.theme-light .markdown-source-view.mod-cm6 .HyperMD-header-1::after{content:'';position:absolute;bottom:0;left:50%;width:40px;height:4px;border-radius:4px;background:var(--h2-bg-gradient);background-size:100% auto;transform:translateX(-50%);transition:width 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s ease}.theme-light .markdown-preview-view h1:hover{color:var(--primary-color);transform:translateY(-2px)}.theme-light .markdown-preview-view h1:hover::after{width:100%}.theme-light.h1-align-left .markdown-preview-view h1,.theme-light.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1{text-align:left;margin-left:0 !important;margin-right:auto !important;padding-left:32px}.theme-light.h1-align-left .markdown-preview-view h1::before,.theme-light.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1::before{content:"";position:absolute;width:10px;height:22px;border-radius:6px;top:45%;transform:translateY(-50%);margin-top:-6px;left:2px;background-color:var(--secondary-color);opacity:0.5;transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);z-index:0}.theme-light.h1-align-left .markdown-preview-view h1::after,.theme-light.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1::after{bottom:auto;width:10px;height:22px;border-radius:6px;top:45%;transform:translateY(-50%);margin-top:4px;left:8px;background:var(--primary-color);mix-blend-mode:multiply;transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1) 0.05s;z-index:1}.theme-light.h1-align-left .markdown-preview-view h1:hover{transform:none;color:var(--primary-color)}.theme-light.h1-align-left .markdown-preview-view h1:hover::before{height:32px;margin-top:0;left:4px;width:6px;opacity:0.3;border-radius:3px}.theme-light.h1-align-left .markdown-preview-view h1:hover::after{height:26px;margin-top:0;left:12px;width:6px;border-radius:3px;box-shadow:0 0 10px color-mix(in srgb, var(--primary-color), transparent 60%)}.theme-light.h2-style-capsule .markdown-preview-view h2,.theme-light.h2-style-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2{color:#fff !important;font-weight:bold;text-decoration:none !important;display:inline-block;width:fit-content;padding:6px 16px;border-radius:8px;background-image:var(--h2-bg-gradient) !important;background-size:200% auto;background-position:0% center;background-repeat:no-repeat;box-shadow:0 2px 5px var(--h2-shadow-color);border:1px solid transparent !important;background-clip:padding-box;overflow:hidden;border-bottom:none !important;transition:background-position 0.5s ease-out, transform 0.4s ease, box-shadow 0.4s ease}.theme-light.h2-style-capsule .markdown-preview-view h2:hover{background-position:100% center;transform:scale(1.01);box-shadow:0 8px 20px var(--h2-shadow-hover)}.theme-light.h2-style-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .cm-formatting-header{color:rgba(255, 255, 255, 0.6) !important}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2,.theme-light.h2-style-twin .markdown-preview-view h2,.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2{background:none !important;box-shadow:none !important;border:none !important;border-radius:0 !important;position:relative;padding-left:20px;padding-right:0;display:block;width:100%;transition:color 0.3s ease}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2 .heading-collapse-indicator,.theme-light.h2-style-twin .markdown-preview-view h2 .heading-collapse-indicator{margin-inline-start:-43px !important}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2::before,.theme-light.h2-style-twin .markdown-preview-view h2::before,.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::before,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::before{content:"";position:absolute;left:0;top:auto;margin-top:0.1em;height:1em;width:5px;background-color:var(--primary-color);border-radius:4px;opacity:1;transition:all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1)}.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::before,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::before{margin-top:0.2em}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2::after,.theme-light.h2-style-twin .markdown-preview-view h2::after,.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::after,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::after{content:"";position:absolute;left:8px;top:auto;margin-top:0.3em;height:0.6em;width:2px;background-color:var(--secondary-color);border-radius:2px;opacity:0.6;transition:all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) 0.05s}.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::after,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::after{margin-top:0.4em}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2:hover,.theme-light.h2-style-twin .markdown-preview-view h2:hover{color:var(--primary-color) !important}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2:hover::before,.theme-light.h2-style-twin .markdown-preview-view h2:hover::before{top:auto;margin-top:0em;height:1.4em;opacity:0.4}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2:hover::after,.theme-light.h2-style-twin .markdown-preview-view h2:hover::after{top:auto;margin-top:0.15em;height:1.1em;width:4px;opacity:1;background-color:var(--primary-color)}.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2 .cm-formatting-header,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2 .cm-formatting-header{color:var(--text-faint) !important;opacity:0.4}.theme-light .markdown-preview-view h3{width:fit-content;padding-left:15px;transition:all 0.3s cubic-bezier(.25, .8, .25, 1)}.theme-light .markdown-preview-view h3::before{content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);width:5px;height:1.3rem;border-radius:4px;background-color:var(--primary-color);transition:all .3s cubic-bezier(.25, .8, .25, 1)}.theme-light .markdown-preview-view h3:hover{padding-left:20px;color:var(--primary-color)}.theme-light .markdown-preview-view h3:hover::before{height:24px;width:7px}.theme-light .markdown-preview-view h4{padding-left:20px}.theme-light .markdown-preview-view h4::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);width:10px;height:10px;border-radius:50%;background-color:var(--primary-color);border:1px solid var(--primary-color);transition:all .3s ease}.theme-light .markdown-preview-view h4:hover{color:var(--light-deep);transform:translateX(6px)}.theme-light .markdown-preview-view h4:hover::before{transform:translateY(-50%) scale(1.3);box-shadow:0 0 0 4px var(--light-lighter)}.theme-light .markdown-preview-view h5{padding-left:20px}.theme-light .markdown-preview-view h5::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);width:10px;height:10px;border-radius:50%;background-color:#fff;border:2px solid var(--primary-color);box-sizing:border-box;transition:all .3s ease}.theme-light .markdown-preview-view h5:hover{color:var(--light-deep);transform:translateX(6px)}.theme-light .markdown-preview-view h5:hover::before{background-color:var(--primary-color);transform:translateY(-50%) scale(1.2);box-shadow:0 0 0 3px var(--light-lighter)}.theme-light .markdown-preview-view h6{padding-left:20px}.theme-light .markdown-preview-view h6::before{content:"-";position:absolute;left:0;top:50%;transform:translateY(-50%);color:var(--primary-color);font-weight:bold;line-height:1;transition:all .3s ease}.theme-light .markdown-preview-view h6:hover{color:var(--light-deep);transform:translateX(6px)}.theme-light .markdown-preview-view h6:hover::before{transform:translateY(-50%) scaleX(1.8)}.theme-dark .markdown-preview-view h1,.theme-dark .markdown-source-view.mod-cm6 .HyperMD-header-1{padding-bottom:12px;border-bottom:none;display:table;width:auto;min-width:120px;text-align:center;margin-top:2em;margin-bottom:1em;margin-left:auto !important;margin-right:auto !important;position:relative}.h1-align-left .markdown-preview-view h1{padding-bottom:0;}.theme-dark .markdown-preview-view h1::after,.theme-dark .markdown-source-view.mod-cm6 .HyperMD-header-1::after{content:'';position:absolute;bottom:0;left:50%;width:40px;height:4px;border-radius:4px;background:var(--h1-underline-color);box-shadow:0 0 5px rgba(255, 85, 85, 0.4);transform:translateX(-50%);transition:width 0.3s cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}.theme-dark .markdown-preview-view h1:hover{text-shadow:var(--glow-shadow-text)}.theme-dark .markdown-preview-view h1:hover::after{width:100%;box-shadow:0 0 15px var(--h1-underline-color)}.theme-dark.h1-align-left .markdown-preview-view h1,.theme-dark.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1{text-align:left;margin-left:0 !important;margin-right:auto !important;padding-left:32px}.theme-dark.h1-align-left .markdown-preview-view h1::before,.theme-dark.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1::before{content:"";position:absolute;top:45%;transform:translateY(-50%);margin-top:-6px;left:2px;width:10px;height:22px;border-radius:6px;background-color:var(--secondary-color);opacity:0.6;transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);z-index:0}.theme-dark.h1-align-left .markdown-preview-view h1::after,.theme-dark.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1::after{bottom:auto;top:45%;transform:translateY(-50%);margin-top:4px;left:8px;width:10px;height:22px;border-radius:6px;background:var(--primary-color);mix-blend-mode:screen;transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1) 0.05s;z-index:1}.theme-dark.h1-align-left .markdown-preview-view h1:hover{text-shadow:var(--glow-shadow-text)}.theme-dark.h1-align-left .markdown-preview-view h1:hover::before{height:32px;margin-top:0;left:4px;width:6px;opacity:0.4}.theme-dark.h1-align-left .markdown-preview-view h1:hover::after{height:26px;margin-top:0;left:12px;width:6px;box-shadow:0 0 15px var(--primary-color)}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2,.theme-dark.h2-style-dark-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2{width:fit-content;padding:5px 16px;border-radius:8px;display:inline-block;background-color:rgba(255, 255, 255, 0.02);background-image:var(--h2-bg-image);background-repeat:no-repeat;background-position:center bottom;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border-top:1px solid rgba(255, 255, 255, 0.08);border-left:1px solid transparent;border-right:1px solid transparent;border-bottom:1px solid transparent;position:relative;z-index:1;overflow:hidden;transition:color 0.5s ease, transform 0.5s ease, box-shadow 0.5s ease}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2::after,.theme-dark.h2-style-dark-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2::after{content:"";position:absolute;inset:0;z-index:-1;background-image:var(--h2-bg-image-hover);background-repeat:no-repeat;background-position:center bottom;opacity:0;transition:opacity 0.5s ease}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2:hover{color:var(--primary-color);text-shadow:var(--glow-shadow-text);box-shadow:0 4px 12px rgba(0, 0, 0, 0.3);transform:translateY(-1px)}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2:hover::after{opacity:1}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2,.theme-dark.h2-style-dark-twin .markdown-preview-view h2,.theme-dark:not(.h2-style-dark-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2,.theme-dark.h2-style-dark-twin .markdown-source-view.mod-cm6 .HyperMD-header-2{background:none !important;box-shadow:none !important;border:none !important;border-radius:0 !important;backdrop-filter:none !important;-webkit-backdrop-filter:none !important;position:relative;padding-left:20px;padding-right:0;display:block;width:100%;transition:color 0.3s ease}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2::before,.theme-dark.h2-style-dark-twin .markdown-preview-view h2::before,.theme-dark:not(.h2-style-dark-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::before,.theme-dark.h2-style-dark-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::before{content:"";position:absolute;left:0;top:auto;margin-top:0.2em;height:1em;width:5px;background-color:var(--primary-color);border-radius:4px;opacity:0.8;box-shadow:0 0 8px color-mix(in srgb, var(--primary-color), transparent 50%);transition:all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1)}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2::after,.theme-dark.h2-style-dark-twin .markdown-preview-view h2::after,.theme-dark:not(.h2-style-dark-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::after,.theme-dark.h2-style-dark-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::after{content:"";position:absolute;left:8px;top:auto;margin-top:0.4em;height:0.6em;width:2px;background-color:var(--secondary-color);border-radius:2px;opacity:0.6;transition:all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) 0.05s}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2:hover,.theme-dark.h2-style-dark-twin .markdown-preview-view h2:hover{color:var(--primary-color) !important;text-shadow:var(--glow-shadow-text)}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2:hover::before,.theme-dark.h2-style-dark-twin .markdown-preview-view h2:hover::before{top:auto;margin-top:0em;height:1.4em;opacity:0.5}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2:hover::after,.theme-dark.h2-style-dark-twin .markdown-preview-view h2:hover::after{top:auto;margin-top:0.15em;height:1.1em;width:4px;opacity:1;background-color:var(--primary-color);box-shadow:0 0 12px var(--primary-color)}.theme-dark .markdown-preview-view h3{padding-left:15px;display:block;transition:padding-left 0.3s ease, color 0.3s ease}.theme-dark .markdown-preview-view h3::before{content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);width:4px;height:1.3rem;background:var(--primary-color);border-radius:2px;transition:all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);opacity:0.8}.theme-dark .markdown-preview-view h3:hover{color:var(--primary-color);padding-left:20px;text-shadow:var(--glow-shadow-text)}.theme-dark .markdown-preview-view h3:hover::before{height:24px;opacity:1;box-shadow:var(--glow-shadow-box)}.theme-dark .markdown-preview-view h4{display:flex;align-items:center}.theme-dark .markdown-preview-view h4::before{content:"";margin-right:10px;display:inline-block;background-color:var(--primary-color);width:8px;height:8px;border-radius:50%;transition:all 0.3s ease;flex-shrink:0}.theme-dark .markdown-preview-view h4:hover{color:var(--primary-color);text-shadow:var(--glow-shadow-text);transform:translateX(5px)}.theme-dark .markdown-preview-view h4:hover::before{transform:scale(1.2);box-shadow:var(--glow-shadow-box)}.theme-dark .markdown-preview-view h5{display:flex;align-items:center}.theme-dark .markdown-preview-view h5::before{content:"";margin-right:10px;display:inline-block;background-color:transparent;border:1.5px solid var(--primary-color);width:8px;height:8px;border-radius:50%;box-sizing:border-box;transition:all 0.3s ease;flex-shrink:0}.theme-dark .markdown-preview-view h5:hover{color:var(--primary-color);text-shadow:var(--glow-shadow-text);transform:translateX(5px)}.theme-dark .markdown-preview-view h5:hover::before{background-color:transparent;border-color:var(--primary-color);box-shadow:var(--glow-shadow-box);transform:scale(1.2)}.theme-dark .markdown-preview-view h6{display:flex;align-items:center}.theme-dark .markdown-preview-view h6::before{content:"-";color:var(--primary-color);margin-right:11px;display:inline-block;font-weight:bold;transition:all 0.3s ease}.theme-dark .markdown-preview-view h6:hover{color:var(--primary-color);text-shadow:var(--glow-shadow-text);transform:translateX(5px)}.theme-dark .markdown-preview-view h6:hover::before{text-shadow:var(--glow-shadow-text);transform:scaleX(1.5)}.markdown-preview-view h3::after,.markdown-preview-view h4::after,.markdown-preview-view h5::after,.markdown-preview-view h6::after{content:" ";display:inline-block;height:1.2em;width:1.2em;vertical-align:top;margin-left:8px;background-color:var(--primary-color);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;mask-repeat:no-repeat;mask-position:center;mask-size:contain;opacity:0.5}.theme-light h3::after,.theme-light h4::after,.theme-light h5::after,.theme-light h6::after{background-color:var(--light-light) !important;opacity:0.5}.markdown-preview-view h3::after{-webkit-mask-image:var(--h3-icon-shape);mask-image:var(--h3-icon-shape)}.markdown-preview-view h4::after{-webkit-mask-image:var(--h4-icon-shape);mask-image:var(--h4-icon-shape)}.markdown-preview-view h5::after{-webkit-mask-image:var(--h5-icon-shape);mask-image:var(--h5-icon-shape)}.markdown-preview-view h6::after{-webkit-mask-image:var(--h6-icon-shape);mask-image:var(--h6-icon-shape)}.markdown-source-view.mod-cm6 .HyperMD-header{font-weight:bold;line-height:1.4;position:relative}.markdown-source-view.mod-cm6 .cm-formatting-header{color:var(--primary-color);font-family:var(--font-monospace);font-weight:normal;margin-right:8px;opacity:0.4}.markdown-source-view.mod-cm6 .HyperMD-header-1{text-align:center;justify-content:center;border-bottom:none}.markdown-source-view.mod-cm6 .HyperMD-header-1::after{content:"";display:block;width:40px;height:4px;border-radius:4px;background:var(--primary-color);background-image:var(--h2-bg-gradient, linear-gradient(to right, var(--primary-color), var(--primary-color)));margin:8px auto 0 auto;opacity:0.8}.markdown-source-view.mod-cm6 .HyperMD-header-3{padding-left:20px}.markdown-source-view.mod-cm6 .HyperMD-header-3::before{content:"";position:absolute;margin-top:0.3rem;left:0;width:5px;height:1.3rem;border-radius:4px;background-color:var(--primary-color);opacity:0.8;pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header-4{padding-left:20px}.markdown-source-view.mod-cm6 .HyperMD-header-4::before{content:"";position:absolute;margin-top:0.46rem;left:0;width:10px;height:10px;border-radius:50%;background-color:var(--primary-color);border:1px solid var(--primary-color);pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header-5{padding-left:20px}.markdown-source-view.mod-cm6 .HyperMD-header-5::before{content:"";position:absolute;margin-top:0.5rem;left:0;width:10px;height:10px;border-radius:50%;background-color:transparent;border:2px solid var(--primary-color);box-sizing:border-box;background-color:var(--bg-color, transparent);pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header-6{padding-left:20px}.markdown-source-view.mod-cm6 .HyperMD-header-6::before{content:"-";position:absolute;left:0;color:var(--primary-color);font-weight:bold;line-height:1.4;font-family:var(--font-monospace);pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header:hover::before{opacity:1;border-color:var(--primary-color)}.markdown-source-view.mod-cm6 .HyperMD-header-3::after,.markdown-source-view.mod-cm6 .HyperMD-header-4::after,.markdown-source-view.mod-cm6 .HyperMD-header-5::after,.markdown-source-view.mod-cm6 .HyperMD-header-6::after{content:"";display:inline-block;vertical-align:top;width:1.2em;height:1.2em;margin-left:8px;background-color:var(--primary-color);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;mask-repeat:no-repeat;mask-position:center;mask-size:contain;opacity:0.3;pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header-3::after{-webkit-mask-image:var(--h3-icon-shape);mask-image:var(--h3-icon-shape)}.markdown-source-view.mod-cm6 .HyperMD-header-4::after{-webkit-mask-image:var(--h4-icon-shape);mask-image:var(--h4-icon-shape)}.markdown-source-view.mod-cm6 .HyperMD-header-5::after{-webkit-mask-image:var(--h5-icon-shape);mask-image:var(--h5-icon-shape)}.markdown-source-view.mod-cm6 .HyperMD-header-6::after{-webkit-mask-image:var(--h6-icon-shape);mask-image:var(--h6-icon-shape)}.markdown-preview-view ul>li::marker,.markdown-preview-view ol>li::marker{color:var(--primary-color)}.markdown-preview-view em{padding:0 3px 0 0;color:var(--secondary-color)}.markdown-preview-view ul{list-style-type:disc}.markdown-preview-view ul ul{list-style-type:circle}.markdown-preview-view ul ul ul{list-style-type:square}.markdown-preview-view ol{list-style-type:decimal}.markdown-preview-view ol ol{list-style-type:lower-alpha}.markdown-preview-view ol ol ol{list-style-type:lower-roman}.markdown-preview-view ul>li>ol{padding-left:25px}.markdown-preview-view li{position:relative}.markdown-preview-view li::before{content:"";position:absolute;top:calc(var(--line-height-customize) * 1em);height:calc(100% - (var(--line-height-customize) * 1.5em));bottom:0;left:-18px;border-left:1px solid var(--primary-color);opacity:0.5;pointer-events:none}.markdown-preview-view ul>li::before{left:-0.83rem}.markdown-preview-view>div>ul>li::before,.markdown-preview-view>div>ol>li::before{display:none}.markdown-preview-view li.task-list-item::before{left:-0.7rem;height:calc(100% - var(--line-height-customize) * 1.4em)}.markdown-rendered.show-indentation-guide li>ul::before,.markdown-rendered.show-indentation-guide li>ol::before{display:none !important;border:none !important}.el-ol ol li{margin-left:35px}.markdown-source-view.mod-cm6 .HyperMD-list-line{--list-color:var(--text-muted)}.markdown-source-view.mod-cm6 .HyperMD-list-line-1,.markdown-source-view.mod-cm6 .HyperMD-list-line-2,.markdown-source-view.mod-cm6 .HyperMD-list-line-3,.markdown-source-view.mod-cm6 .HyperMD-list-line-4,.markdown-source-view.mod-cm6 .HyperMD-list-line-5,.markdown-source-view.mod-cm6 .HyperMD-list-line-6{--list-color:var(--primary-color)}.markdown-source-view.mod-cm6 .list-bullet{color:transparent !important;position:relative;margin-right:12px !important;display:inline-block}.markdown-source-view.mod-cm6 .list-bullet:after{content:"";position:absolute;top:50%;left:50%;transform:translate(-50%, -50%) scale(1.1);height:6px;width:6px;border-radius:50%;background-color:var(--list-color) !important;transition:all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)}.markdown-source-view.mod-cm6 .HyperMD-list-line:hover .list-bullet:after{transform:translate(-50%, -50%) scale(1.6);box-shadow:0 0 8px var(--list-color)}.markdown-source-view.is-live-preview{--list-padding-inline-start:0}.markdown-source-view.mod-cm6 .cm-indent::before{margin-inline-start:3px !important}.markdown-source-view.mod-cm6 .cm-active-indent::before{opacity:1 !important;box-shadow:0 0 8px var(--primary-color);z-index:1}.markdown-source-view.mod-cm6 .HyperMD-list-line .task-list-item-checkbox{border-color:var(--list-color) !important}.markdown-source-view.mod-cm6 .HyperMD-list-line .task-list-item-checkbox:checked{background-color:var(--list-color) !important;box-shadow:0 0 5px var(--list-color)}.markdown-source-view.mod-cm6 .list-number{color:var(--primary-color) !important;font-family:"Cascadia Code", "Lucida Console", monospace !important;font-weight:bold;margin-right:4px}.image-embed[alt*="right" i],.image-embed[alt*="+R" i],.image-embed[alt*="left" i],.image-embed[alt*="+L" i],.image-embed[alt*="center" i],.image-embed[alt*="+C" i],.image-embed[alt*="banner" i]{display:flex !important;width:100% !important;margin-top:0.5rem;margin-bottom:0.5rem}.image-embed[alt*="right" i],.image-embed[alt*="+R" i]{justify-content:flex-end}.image-embed[alt*="left" i],.image-embed[alt*="+L" i]{justify-content:flex-start}.image-embed[alt*="center" i],.image-embed[alt*="+C" i]{justify-content:center}.image-embed[alt*="right" i] img,.image-embed[alt*="+R" i] img,.image-embed[alt*="left" i] img,.image-embed[alt*="+L" i] img,.image-embed[alt*="center" i] img,.image-embed[alt*="+C" i] img{border-radius:8px;box-shadow:0 4px 15px rgba(0,0,0,0.05)}.image-embed[alt*="banner" i]{justify-content:center}.image-embed[alt*="banner" i] img{width:100% !important;max-height:250px;object-fit:cover;border-radius:12px;box-shadow:0 4px 15px rgba(0,0,0,0.05)}.markdown-preview-view ul.contains-task-list{margin-left:10px}.markdown-preview-view ul.contains-task-list{margin-left:10px}.markdown-preview-view input[type="checkbox"],.markdown-preview-view .task-list-item-checkbox{-webkit-appearance:none !important;appearance:none !important;background:transparent !important;border:none !important;border-radius:0 !important;outline:none !important;box-shadow:none !important;position:absolute !important;margin:0 !important;padding:0 !important;left:-1.3rem !important;top:calc((var(--line-height-customize) * 1.1rem - var(--checkbox-size)) / 2) !important;width:var(--checkbox-size) !important;height:var(--checkbox-size) !important;z-index:10;-webkit-mask-image:none !important;mask-image:none !important}.markdown-preview-view input[type="checkbox"]::before,.markdown-preview-view .task-list-item-checkbox::before{content:"" !important;display:block !important;position:absolute !important;inset:0 !important;width:1.2rem !important;height:1.2rem !important;border-radius:50% !important;background-color:var(--checkbox-bg-unchecked) !important;border:2px solid var(--checkbox-border-unchecked) !important;box-sizing:border-box !important;transition:all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.4);z-index:1}.markdown-preview-view input[type="checkbox"]:checked::before,.markdown-preview-view .task-list-item-checkbox:checked::before{border:1px solid var(--primary-color) !important;background-color:var(--checkbox-bg-checked) !important;box-shadow:var(--checkbox-shadow-checked) !important;animation:task-pulse 0.4s forwards}.markdown-preview-view input[type="checkbox"]::after,.markdown-preview-view .task-list-item-checkbox::after{content:"" !important;display:block !important;position:absolute !important;z-index:2 !important;top:45% !important;left:50% !important;width:0.45rem !important;height:0.25rem !important;background-color:transparent !important;-webkit-mask-image:none !important;mask-image:none !important;border:2.5px solid var(--checkmark-color) !important;border-top:0 !important;border-right:0 !important;transform:translate(-50%, -50%) rotate(-45deg) scale(0);opacity:0;transition:all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.4)}.markdown-preview-view input[type="checkbox"]:checked::after,.markdown-preview-view .task-list-item-checkbox:checked::after{opacity:1 !important;transform:translate(-50%, -50%) rotate(-45deg) scale(1) !important;border-color:var(--checkmark-color) !important}.markdown-preview-view .task-list-item[data-task="/"]{color:var(--text-normal) !important;text-decoration:none !important;opacity:1 !important}.markdown-preview-view .task-list-item[data-task="/"] p,.markdown-preview-view .task-list-item[data-task="/"] strong,.markdown-preview-view .task-list-item[data-task="/"] em,.markdown-preview-view .task-list-item[data-task="/"] code{text-decoration:none !important;color:inherit !important}.markdown-preview-view .task-list-item[data-task="/"] input[type="checkbox"]:checked::after{content:"" !important;border:none !important;width:6px !important;height:6px !important;border-radius:50% !important;background-color:var(--checkmark-color) !important;top:50% !important;left:50% !important;transform:translate(-50%, -50%) !important}.markdown-preview-view .task-list-item[data-task="-"]{color:var(--text-muted) !important;text-decoration:line-through !important;opacity:0.7 !important}.markdown-preview-view .task-list-item[data-task="-"] strong,.markdown-preview-view .task-list-item[data-task="-"] em{text-decoration:line-through !important;color:inherit !important}.markdown-preview-view .task-list-item[data-task="-"] input[type="checkbox"]:checked::before{background-color:var(--text-muted) !important;border-color:var(--text-muted) !important;box-shadow:none !important}.markdown-preview-view .task-list-item[data-task="-"] input[type="checkbox"]:checked::after{content:"\2715" !important;border:none !important;transform:none !important;background:transparent !important;font-size:13px !important;font-weight:800 !important;color:#ffffff !important;display:flex !important;align-items:center;justify-content:center;width:100% !important;height:100% !important;top:-1px !important;left:-0.3px !important}@keyframes task-pulse{0%{transform:scale(1)}50%{transform:scale(1.15)}100%{transform:scale(1)}}.markdown-preview-view .task-list-item{position:relative;list-style:none;padding-left:4px;min-height:calc(var(--line-height-customize) * 1em);transition:color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), opacity 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), text-decoration-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) !important;text-decoration:line-through !important;text-decoration-color:transparent !important;text-decoration-thickness:2px !important}.markdown-preview-view .task-list-item.is-checked{color:#888 !important;opacity:0.8;text-decoration-color:var(--text-color-secondary) !important}.markdown-preview-view .task-list-item.is-checked p,.markdown-preview-view .task-list-item.is-checked strong,.markdown-preview-view .task-list-item.is-checked em,.markdown-preview-view .task-list-item.is-checked mark,.markdown-preview-view .task-list-item.is-checked code{text-decoration:line-through !important;text-decoration-color:var(--text-color-secondary) !important;text-decoration-thickness:2px !important;color:inherit !important;opacity:1 !important}.markdown-preview-view blockquote p,.HyperMD-quote.HyperMD-quote-1.cm-line{line-height:var(--blockquote-line-height)}.theme-dark .markdown-preview-view blockquote{position:relative;margin:20px 0;padding:18px 20px 18px 48px;color:var(--text-color-secondary);background-color:rgba(0, 0, 0, 0.2);border:1px solid color-mix(in srgb, var(--secondary-color), transparent 70%);border-radius:16px;transition:all 0.3s ease}.theme-dark .markdown-preview-view blockquote::before{content:"💡";position:absolute;left:14px;top:18px;font-size:20px;line-height:1;filter:grayscale(1);opacity:0.8;transform:rotate(30deg);transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)}.theme-dark .markdown-preview-view blockquote p{color:var(--text-color-secondary);margin-block-start:0;margin-block-end:0;margin-bottom:0.5em}.theme-dark .markdown-preview-view blockquote p:last-child{margin-bottom:0}.theme-dark .markdown-preview-view blockquote:hover{border-color:var(--primary-color);background-color:color-mix(in srgb, var(--hover-background-color), transparent 95%);box-shadow:0 0 15px color-mix(in srgb, var(--hover-background-color), transparent 90%), inset 0 0 10px color-mix(in srgb, var(--hover-background-color), transparent 95%);transform:scale(1.01)}.theme-dark .markdown-preview-view blockquote:hover::before{filter:grayscale(0);opacity:1;transform:rotate(0deg);text-shadow:0 0 10px var(--primary-color)}.theme-light .markdown-preview-view blockquote{position:relative;margin:20px 0;padding:18px 20px 18px 48px;background-color:var(--blockquote-background-color);border:1px solid color-mix(in srgb, var(--primary-color), transparent 80%);border-radius:16px;color:var(--text-muted);transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), background-color 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease}.theme-light .markdown-preview-view blockquote::before{content:"✨";position:absolute;left:14px;top:18px;font-size:20px;line-height:1;font-family:"Segoe UI Emoji", "Apple Color Emoji", sans-serif;filter:none;opacity:1;transform:rotate(30deg);transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)}.theme-light .markdown-preview-view blockquote p{color:var(--text-muted);margin-block-start:0;margin-block-end:0;margin-bottom:0.5em}.theme-light .markdown-preview-view blockquote p:last-child{margin-bottom:0}.theme-light .markdown-preview-view blockquote:hover{transform:scale(1.02);background-color:color-mix(in srgb, var(--primary-color), white 92%);border-color:var(--primary-color);box-shadow:0 8px 20px color-mix(in srgb, var(--primary-color), transparent 85%)}.theme-light .markdown-preview-view blockquote:hover::before{transform:rotate(0deg);text-shadow:0 0 8px var(--primary-color)}.markdown-preview-view a.internal-link,.markdown-preview-view a.external-link,.markdown-source-view.mod-cm6 .cm-link .cm-underline,.markdown-source-view.mod-cm6 .cm-table-widget a{color:var(--secondary-color) !important;text-decoration:none !important;font-weight:500;padding:0 2px;margin:0;border-radius:4px;position:relative;border-bottom:none !important;background-image:none !important;padding-right:2px !important;cursor:pointer;transition:all 0.3s ease}.markdown-preview-view a.internal-link::before,.markdown-preview-view a.external-link::before,.markdown-source-view.mod-cm6 .cm-link .cm-underline::before,.markdown-source-view.mod-cm6 .cm-table-widget a::before{content:"[";display:inline-block;color:var(--text-muted);margin-right:1px;opacity:0.7;transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.3s, opacity 0.3s}.markdown-preview-view a.internal-link::after,.markdown-preview-view a.external-link::after,.markdown-source-view.mod-cm6 .cm-link .cm-underline::after,.markdown-source-view.mod-cm6 .cm-table-widget a::after{content:"]";display:inline-block;color:var(--text-muted);margin-left:1px;opacity:0.7;transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.3s, opacity 0.3s}.markdown-preview-view a.internal-link:hover,.markdown-preview-view a.external-link:hover,.markdown-source-view.mod-cm6 .cm-link .cm-underline:hover,.markdown-source-view.mod-cm6 .cm-table-widget a:hover{background-color:color-mix(in srgb, var(--primary-color), transparent 90%);color:var(--primary-color) !important;text-decoration:none !important}.markdown-preview-view a.internal-link:hover::before,.markdown-preview-view a.external-link:hover::before,.markdown-source-view.mod-cm6 .cm-link .cm-underline:hover::before,.markdown-source-view.mod-cm6 .cm-table-widget a:hover::before{transform:translateX(-4px);color:var(--primary-color);font-weight:bold;opacity:1}.markdown-preview-view a.internal-link:hover::after,.markdown-preview-view a.external-link:hover::after,.markdown-source-view.mod-cm6 .cm-link .cm-underline:hover::after,.markdown-source-view.mod-cm6 .cm-table-widget a:hover::after{transform:translateX(4px);color:var(--primary-color);font-weight:bold;opacity:1}.markdown-preview-view .external-link-icon,.markdown-source-view.mod-cm6 .cm-link .external-link,.markdown-source-view.mod-cm6 .cm-formatting-link-string.external-link,.markdown-source-view.mod-cm6 .cm-url.external-link{display:none !important;width:0 !important;height:0 !important;content:none !important;background-image:none !important;padding:0 !important;margin:0 !important}.markdown-preview-view table td a,.markdown-source-view.mod-cm6 .cm-table-widget a{padding:0 2px !important}.markdown-preview-view mark,.markdown-source-view.mod-cm6 mark,.markdown-source-view.mod-cm6 .cm-highlight{padding:0 2px;margin:0;border-radius:4px;font-weight:inherit;color:inherit;-webkit-box-decoration-break:clone;box-decoration-break:clone}.markdown-preview-view mark::before,.markdown-preview-view mark::after,.markdown-source-view.mod-cm6 mark::before,.markdown-source-view.mod-cm6 mark::after,.markdown-source-view.mod-cm6 .cm-highlight::before,.markdown-source-view.mod-cm6 .cm-highlight::after{content:none !important;display:none !important}.markdown-preview-view mark:not([style*="background"]),.markdown-source-view.mod-cm6 mark:not([style*="background"]),.markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]){background-color:transparent !important;background-repeat:no-repeat;background-position:0 100%;transition:background-size 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.3s ease, text-shadow 0.3s ease, box-shadow 0.3s ease}body.theme-light .markdown-preview-view mark:not([style*="background"]),body.theme-light .markdown-source-view.mod-cm6 mark:not([style*="background"]),body.theme-light .markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]){background-image:linear-gradient(to top, color-mix(in srgb, var(--primary-color), transparent 60%), transparent);background-size:100% 40%;color:var(--text-normal)}body.theme-light .markdown-preview-view mark:not([style*="background"]):hover,body.theme-light .markdown-source-view.mod-cm6 mark:not([style*="background"]):hover,body.theme-light .markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]):hover{background-size:100% 100%;background-image:linear-gradient(to top, color-mix(in srgb, var(--primary-color), transparent 40%), color-mix(in srgb, var(--primary-color), transparent 80%))}body.theme-dark .markdown-preview-view mark:not([style*="background"]),body.theme-dark .markdown-source-view.mod-cm6 mark:not([style*="background"]),body.theme-dark .markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]){background-image:linear-gradient(to top, color-mix(in srgb, var(--primary-color), transparent 50%), transparent) !important;background-size:100% 40%;color:color-mix(in srgb, var(--primary-color), white 20%) !important;text-shadow:none;box-shadow:none}body.theme-dark .markdown-preview-view mark:not([style*="background"]):hover,body.theme-dark .markdown-source-view.mod-cm6 mark:not([style*="background"]):hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]):hover{background-size:100% 100%;background-image:linear-gradient(to top, color-mix(in srgb, var(--primary-color), transparent 20%), color-mix(in srgb, var(--primary-color), transparent 80%)) !important;color:#fff !important;text-shadow:0 0 10px var(--primary-color);box-shadow:0 0 15px color-mix(in srgb, var(--primary-color), transparent 80%);transform:none}.markdown-preview-view strong,.markdown-source-view.mod-cm6 .cm-strong,.markdown-source-view.mod-cm6 strong{font-weight:bold;display:inline;position:relative;border-bottom:2px solid transparent;-webkit-box-decoration-break:clone;box-decoration-break:clone;transition:border-color 0.3s ease, color 0.3s ease, text-shadow 0.3s ease}body.theme-dark .markdown-preview-view strong,body.theme-dark .markdown-source-view.mod-cm6 .cm-strong,body.theme-dark .markdown-source-view.mod-cm6 strong{color:var(--primary-color)}body.theme-dark .markdown-preview-view strong:hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-strong:hover,body.theme-dark .markdown-source-view.mod-cm6 strong:hover{border-bottom-color:var(--primary-color);text-shadow:0 0 10px var(--primary-color);z-index:1}body.theme-light .markdown-preview-view strong,body.theme-light .markdown-source-view.mod-cm6 .cm-strong,body.theme-light .markdown-source-view.mod-cm6 strong{color:var(--text-bold)}body.theme-light .markdown-preview-view strong:hover,body.theme-light .markdown-source-view.mod-cm6 .cm-strong:hover,body.theme-light .markdown-source-view.mod-cm6 strong:hover{color:var(--primary-color) !important;border-bottom-color:color-mix(in srgb, var(--primary-color), transparent 70%);text-shadow:0 2px 10px color-mix(in srgb, var(--primary-color), transparent 60%)}.markdown-preview-view em,.markdown-source-view.mod-cm6 .cm-em,.markdown-source-view.mod-cm6 em{font-style:italic;text-decoration:none !important;padding-bottom:1px;background-repeat:repeat-x;background-position:0 100%;background-size:6px 3px;transition:color 0.2s ease, -webkit-text-stroke 0.2s ease, background-image 0.2s ease;-webkit-box-decoration-break:clone;box-decoration-break:clone}.markdown-preview-view em::after,.markdown-source-view.mod-cm6 .cm-em::after,.markdown-source-view.mod-cm6 em::after{content:none !important;display:none !important}@keyframes stitchFlow{from{background-position-x:0}to{background-position-x:6px}}body.theme-light .markdown-preview-view em,body.theme-light .markdown-source-view.mod-cm6 .cm-em,body.theme-light .markdown-source-view.mod-cm6 em{color:var(--secondary-color);background-image:linear-gradient(-45deg, transparent 35%, color-mix(in srgb, var(--secondary-color), transparent 60%) 35%, color-mix(in srgb, var(--secondary-color), transparent 60%) 65%, transparent 65%)}body.theme-light .markdown-preview-view em:hover,body.theme-light .markdown-source-view.mod-cm6 .cm-em:hover,body.theme-light .markdown-source-view.mod-cm6 em:hover{color:var(--primary-color);background-image:linear-gradient(-45deg, transparent 35%, var(--primary-color) 35%, var(--primary-color) 65%, transparent 65%);font-weight:normal;-webkit-text-stroke:0.6px var(--primary-color);animation:stitchFlow 0.5s linear infinite}body.theme-dark .markdown-preview-view em,body.theme-dark .markdown-source-view.mod-cm6 .cm-em,body.theme-dark .markdown-source-view.mod-cm6 em{color:var(--secondary-color);background-image:linear-gradient(-45deg, transparent 35%, color-mix(in srgb, var(--secondary-color), white 20%) 35%, color-mix(in srgb, var(--secondary-color), white 20%) 65%, transparent 65%)}body.theme-dark .markdown-preview-view em:hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-em:hover,body.theme-dark .markdown-source-view.mod-cm6 em:hover{color:var(--primary-color);background-image:linear-gradient(-45deg, transparent 35%, var(--primary-color) 35%, var(--primary-color) 65%, transparent 65%);font-weight:normal;-webkit-text-stroke:0.5px var(--primary-color);text-shadow:var(--glow-shadow-text);animation:stitchFlow 0.5s linear infinite}.markdown-preview-view s,.markdown-preview-view del,.markdown-source-view.mod-cm6 .cm-strikethrough{text-decoration:line-through;transition:all 0.3s ease}body.theme-dark .markdown-preview-view s,body.theme-dark .markdown-preview-view del,body.theme-dark .markdown-source-view.mod-cm6 .cm-strikethrough{text-decoration-color:var(--primary-color);color:#888}body.theme-dark .markdown-preview-view s:hover,body.theme-dark .markdown-preview-view del:hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-strikethrough:hover{opacity:1;color:var(--primary-color) !important;text-decoration-color:var(--secondary-color);cursor:not-allowed;text-shadow:0 0 8px var(--primary-color)}body.theme-light .markdown-preview-view s,body.theme-light .markdown-preview-view del,body.theme-light .markdown-source-view.mod-cm6 .cm-strikethrough{text-decoration-color:color-mix(in srgb, var(--primary-color), transparent 40%);color:#999}body.theme-light .markdown-preview-view s:hover,body.theme-light .markdown-preview-view del:hover,body.theme-light .markdown-source-view.mod-cm6 .cm-strikethrough:hover{opacity:1;color:var(--text-normal) !important;text-decoration-color:#ff5555;cursor:not-allowed;text-shadow:none}.markdown-preview-view hr{border:none;height:1px;background:linear-gradient(90deg, transparent, var(--primary-color), transparent);position:relative;overflow:visible;opacity:0.5;transition:all 0.3s ease}.markdown-preview-view hr::after{content:'';position:absolute;left:50%;top:50%;transform:translate(-50%, -50%) rotate(45deg);width:8px;height:8px;border:2px solid var(--primary-color);background-color:var(--bg-color);box-sizing:border-box;transition:all 0.3s ease}.markdown-preview-view hr:hover{opacity:1;background:linear-gradient(90deg, transparent, var(--primary-color), transparent)}.markdown-preview-view hr:hover::after{border-color:var(--primary-color);background-color:var(--primary-color);box-shadow:0 0 10px var(--primary-color);transform:translate(-50%, -50%) rotate(225deg) scale(1.5)}.markdown-preview-view table{border-collapse:separate !important;border-spacing:0 !important;width:100%;margin:1.5em 0;border:1px solid var(--border-color);border-radius:var(--table-border-radius);overflow:hidden;background-color:var(--table-bg);backdrop-filter:blur(5px);-webkit-backdrop-filter:blur(5px);line-height:var(--table-line-height)}.markdown-preview-view table th,.markdown-preview-view table td{padding:10px 15px;color:var(--text-color);border-top:none !important;border-left:none !important;border-right:1px solid var(--table-border-inner);border-bottom:1px solid var(--table-border-inner);transition:all 0.2s ease}.markdown-preview-view table th:last-child,.markdown-preview-view table td:last-child{border-right:none !important}.markdown-preview-view table tr:last-child td{border-bottom:none !important}.markdown-preview-view table th{background-color:var(--table-th-bg) !important;color:var(--primary-color);font-weight:bold;white-space:nowrap;border-right:1px solid var(--table-th-border) !important;border-bottom:1px solid var(--table-th-border) !important}.markdown-preview-view table th:last-child{border-right:none !important}.markdown-preview-view table tbody tr:hover td{background-color:var(--table-row-hover-bg)}.markdown-preview-view table tbody td:hover{background-color:var(--table-cell-hover-bg);color:var(--table-cell-hover-text);box-shadow:inset 0 0 0 1px var(--primary-color);cursor:default}.markdown-preview-view table tr:nth-child(2n),.markdown-preview-view table tr:nth-child(2n+1){background-color:transparent !important}.markdown-preview-view table thead tr,.markdown-preview-view table thead tr:nth-child(2n),.markdown-preview-view table thead tr:nth-child(2n+1){background-color:transparent !important}.markdown-preview-view table th{background-color:var(--table-th-bg) !important}.theme-dark .markdown-preview-view table tbody td:hover{text-shadow:0 0 8px var(--primary-color)}.theme-light .markdown-preview-view table tbody td:hover{text-shadow:none}.markdown-source-view.mod-cm6 .cm-table-widget .table-editor{background-color:var(--table-bg) !important;border:1px solid var(--border-color) !important;border-radius:var(--table-border-radius);border-collapse:separate !important;margin-top:1em;margin-bottom:1em;width:100%}.markdown-source-view.mod-cm6 .cm-table-widget thead th{background-color:var(--table-th-bg) !important;color:var(--primary-color) !important;font-weight:bold;border-bottom:1px solid var(--table-th-border) !important;border-right:1px solid var(--table-th-border) !important;border-top:none !important;border-left:none !important;position:relative}.markdown-source-view.mod-cm6 .cm-table-widget tbody td{border-right:1px solid var(--table-border-inner) !important;border-bottom:1px solid var(--table-border-inner) !important;border-top:none !important;border-left:none !important;color:var(--text-color);transition:background-color 0.2s ease}.markdown-source-view.mod-cm6 .cm-table-widget .table-cell-wrapper{padding:10px 15px !important;display:block;min-height:100%}.markdown-source-view.mod-cm6 .cm-table-widget th:last-child,.markdown-source-view.mod-cm6 .cm-table-widget td:last-child{border-right:none !important}.markdown-source-view.mod-cm6 .cm-table-widget tbody tr:last-child td{border-bottom:none !important}.markdown-source-view.mod-cm6 .cm-table-widget tbody tr:hover td{background-color:var(--table-row-hover-bg)}.markdown-source-view.mod-cm6 .cm-table-widget tbody td:hover{background-color:var(--table-cell-hover-bg) !important;box-shadow:inset 0 0 0 1px var(--primary-color) !important}.markdown-source-view.mod-cm6 .cm-table-widget .table-col-drag-handle,.markdown-source-view.mod-cm6 .cm-table-widget .table-row-drag-handle{opacity:0;transition:opacity 0.2s ease;background-color:color-mix(in srgb, var(--border-color), transparent 70%)}.markdown-source-view.mod-cm6 .cm-table-widget th:hover .table-col-drag-handle,.markdown-source-view.mod-cm6 .cm-table-widget th:hover .table-row-drag-handle,.markdown-source-view.mod-cm6 .cm-table-widget td:hover .table-row-drag-handle{opacity:1}.markdown-source-view.mod-cm6 .cm-table-widget .table-row-btn,.markdown-source-view.mod-cm6 .cm-table-widget .table-col-btn{color:var(--text-muted);transition:all 0.2s ease;background-color:transparent}.markdown-source-view.mod-cm6 .cm-table-widget .table-row-btn{width:97%}.markdown-source-view.mod-cm6 .cm-table-widget .table-row-btn:hover,.markdown-source-view.mod-cm6 .cm-table-widget .table-col-btn:hover{border:none;color:var(--primary-color);background-color:transparent;transform:scale(1.1)}.markdown-source-view.mod-cm6 .cm-table-widget .cm-active{background-color:transparent !important}.markdown-rendered button.copy-code-button{top:-4px}.markdown-preview-view pre{position:relative;background-color:var(--code-background) !important;border:1px solid color-mix(in srgb, var(--border-color), transparent 50%) !important;border-radius:var(--code-radius);padding-top:38px !important;padding-bottom:12px;padding-left:0;padding-right:0;margin:20px 0;overflow:hidden;transition:border-color 0.3s ease, box-shadow 0.3s ease}.markdown-preview-view pre:hover{border-color:var(--primary-color) !important;box-shadow:0 4px 12px color-mix(in srgb, var(--primary-color), transparent 85%)}.markdown-preview-view pre::before{content:"";position:absolute;top:0;left:0;width:100%;height:32px;background-color:color-mix(in srgb, var(--primary-color), transparent 96%);background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDUwcHgiIGhlaWdodD0iMTMwcHgiPgogIDxlbGxpcHNlIGN4PSI2NSIgY3k9IjY1IiByeD0iNTAiIHJ5PSI1MiIgc3Ryb2tlPSJyZ2IoMjIwLDYwLDU0KSIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJyZ2IoMjM3LDEwOCw5NikiLz4KICA8ZWxsaXBzZSBjeD0iMjI1IiBjeT0iNjUiIHJ4PSI1MCIgcnk9IjUyIiAgc3Ryb2tlPSJyZ2IoMjE4LDE1MSwzMykiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0icmdiKDI0NywxOTMsODEpIi8+CiAgPGVsbGlwc2UgY3g9IjM4NSIgY3k9IjY1IiByeD0iNTAiIHJ5PSI1MiIgIHN0cm9rZT0icmdiKDI3LDE2MSwzNykiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0icmdiKDEwMCwyMDAsODYpIi8+Cjwvc3ZnPg==);background-repeat:no-repeat;background-size:54px;background-position:12px center;border-bottom:1px solid color-mix(in srgb, var(--border-color), transparent 70%);border-radius:8px 8px 0 0;z-index:5}.markdown-preview-view pre:hover::before{background-color:color-mix(in srgb, var(--primary-color), transparent 95%);border-bottom-color:color-mix(in srgb, var(--primary-color), transparent 80%)}.markdown-preview-view pre code{display:block;padding:0 16px;overflow-x:auto;color:var(--code-normal) !important;font-family:var(--font-monospace);line-height:var(--code-line-height);background-color:transparent !important}.markdown-preview-view pre.language-mermaid{padding-top:0 !important;background:transparent !important;border:none !important;box-shadow:none !important}.markdown-preview-view pre.language-mermaid::before{display:none !important}.markdown-preview-view .copy-code-button{background-color:transparent;color:var(--code-comment);top:4px;right:6px;height:24px;padding:0 8px;border-radius:4px;z-index:10;transition:all 0.2s}.markdown-preview-view .copy-code-button:hover{background-color:var(--primary-color);color:#fff}.markdown-preview-view pre:not([class]){padding-top:12px !important;padding-bottom:12px !important;padding-left:16px !important;padding-right:16px !important;background-color:color-mix(in srgb, var(--primary-color), transparent 96%) !important;border:none !important;border-left:4px solid var(--primary-color) !important;border-radius:4px !important;box-shadow:none !important;margin:16px 0}.markdown-preview-view pre:not([class])::before{content:none !important;display:none !important;height:0 !important;width:0 !important}.markdown-preview-view pre:not([class]) code{color:var(--text-normal) !important;font-family:var(--font-monospace);padding:0 !important;background-color:transparent !important;display:block;white-space:pre-wrap}body.theme-dark .markdown-preview-view pre:not([class]){background-color:rgba(255, 255, 255, 0.03) !important;border-left-color:var(--primary-color) !important}.markdown-source-view.mod-cm6 .HyperMD-codeblock{font-family:var(--font-monospace) !important;line-height:1.5;border-left:1px solid var(--code-border-color, rgba(189, 147, 249, 0.3));border-right:1px solid var(--code-border-color, rgba(189, 147, 249, 0.3))}.theme-dark .markdown-source-view.mod-cm6 .HyperMD-codeblock{background-color:rgba(255, 255, 255, 0.03) !important;color:var(--text-normal)}.theme-light .markdown-source-view.mod-cm6 .HyperMD-codeblock{background-color:var(--code-background) !important;--code-border-color:color-mix(in srgb, var(--primary-color), transparent 85%);border-left:1px solid var(--code-border-color);border-right:1px solid var(--code-border-color);color:var(--code-normal) !important}.markdown-source-view.mod-cm6 .HyperMD-codeblock-begin{border-top-left-radius:8px;border-top-right-radius:8px;padding-top:6px !important;padding-bottom:6px !important;margin-top:12px;position:relative;font-weight:bold;border-top:1px solid var(--code-border-color, rgba(189, 147, 249, 0.3))}.theme-dark .markdown-source-view.mod-cm6 .HyperMD-codeblock-begin{background-color:rgba(255, 255, 255, 0.08) !important;color:var(--secondary-color) !important}.theme-light .markdown-source-view.mod-cm6 .HyperMD-codeblock-begin{background-color:var(--code-block-header-bg, #f7f7f7) !important;color:var(--primary-color) !important}.markdown-source-view.mod-cm6 .HyperMD-codeblock-end{border-bottom-left-radius:8px;border-bottom-right-radius:8px;margin-bottom:12px;border-bottom:1px solid var(--code-border-color, rgba(189, 147, 249, 0.3))}.theme-dark .markdown-source-view.mod-cm6 .HyperMD-codeblock-end{color:var(--text-muted) !important}.theme-light .markdown-source-view.mod-cm6 .HyperMD-codeblock-end{color:var(--code-comment) !important}.theme-dark .markdown-source-view.mod-cm6 .HyperMD-codeblock.cm-active{background-color:rgba(255, 255, 255, 0.05) !important}.theme-light .markdown-source-view.mod-cm6 .HyperMD-codeblock.cm-active{background-color:color-mix(in srgb, var(--primary-color), transparent 94%) !important}.cm-keyword{color:var(--code-keyword) !important}.cm-def{color:var(--code-function) !important}.cm-string{color:var(--code-string) !important}.cm-number{color:var(--code-value) !important}.cm-comment{color:var(--code-comment) !important}.cm-variable{color:var(--code-operator) !important}.cm-property{color:var(--code-property) !important}.cm-type{color:var(--code-function) !important}.cm-atom{color:var(--code-value) !important}.theme-light .cm-punctuation,.theme-light .cm-operator{color:var(--code-punctuation, #555) !important}.callout{padding:12px 16px !important;margin-block:1em !important;border:none !important;border-radius:12px !important;position:relative !important;overflow:hidden !important;mix-blend-mode:normal;transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.3s ease, background-color 0.3s ease !important}.callout:hover{z-index:5}.callout-title{display:inline-flex !important;align-items:center;margin-bottom:12px !important;padding:4px 12px !important;border-radius:50px !important;font-weight:700;font-size:0.9em;line-height:1.2;color:inherit !important;background-color:rgba(255, 255, 255, 0.6) !important;border:1px solid rgba(0, 0, 0, 0.05) !important;position:relative;z-index:2}.callout-icon{display:inline-flex !important;align-items:center;justify-content:center;margin-right:6px !important;flex:0 0 auto !important;color:currentColor !important}.callout-icon svg{width:16px !important;height:16px !important;display:block !important;opacity:1 !important;fill:currentColor !important;stroke:currentColor !important;stroke-width:2px}.callout::after{content:"✨";position:absolute !important;right:-10px !important;bottom:-15px !important;font-family:"Segoe UI Emoji", "Apple Color Emoji", sans-serif;font-size:80px !important;line-height:1;opacity:0.12 !important;transform:rotate(-15deg);filter:grayscale(100%);pointer-events:none;z-index:0;transition:all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) !important}.callout:hover::after{transform:rotate(0deg) scale(1.1) !important;opacity:0.25 !important;right:0px !important;bottom:-5px !important;filter:grayscale(0%) !important}.callout-content{position:relative;z-index:2}.callout-content ul.contains-task-list{margin-left:2px}.markdown-source-view.mod-cm6 .callout-content ul.contains-task-list input.task-list-item-checkbox{transform:translateY(4px)}.theme-light .callout[data-callout="note"],.theme-light .callout[data-callout="info"],.theme-light .callout[data-callout="todo"]{background-color:rgba(48, 107, 214, 0.1) !important}.theme-light .callout[data-callout="note"] .callout-title{color:#6c5ce7 !important}.theme-light .callout[data-callout="note"]:hover{background-color:rgba(108, 92, 231, 0.15) !important}.theme-light .callout[data-callout="note"]::after{content:"📝";color:#6c5ce7}.theme-light .callout[data-callout="info"]::after{content:"ℹ️";color:#6c5ce7}.theme-light .callout[data-callout="todo"]::after{content:"✅";color:#6c5ce7}.theme-light .callout[data-callout="tip"]{background-color:rgba(0, 184, 148, 0.1) !important}.theme-light .callout[data-callout="tip"] .callout-title{color:#00b894 !important}.theme-light .callout[data-callout="tip"]:hover{background-color:rgba(0, 184, 148, 0.15) !important}.theme-light .callout[data-callout="tip"]::after{content:"💡";color:#00b894}.theme-light .callout[data-callout="warning"]{background-color:rgba(253, 203, 110, 0.15) !important}.theme-light .callout[data-callout="warning"] .callout-title{color:#e17055 !important}.theme-light .callout[data-callout="warning"]:hover{background-color:rgba(253, 203, 110, 0.2) !important}.theme-light .callout[data-callout="warning"]::after{content:"⚠️";color:#e17055}.theme-light .callout[data-callout="important"]{background-color:rgba(255, 118, 117, 0.12) !important}.theme-light .callout[data-callout="important"] .callout-title{color:#ff7675 !important}.theme-light .callout[data-callout="important"]:hover{background-color:rgba(255, 118, 117, 0.18) !important}.theme-light .callout[data-callout="important"]::after{content:"📌";color:#ff7675}.theme-light .callout[data-callout="caution"],.theme-light .callout[data-callout="bug"]{background-color:rgba(214, 48, 49, 0.08) !important}.theme-light .callout[data-callout="caution"] .callout-title{color:#d63031 !important}.theme-light .callout[data-callout="caution"]:hover{background-color:rgba(214, 48, 49, 0.12) !important}.theme-light .callout[data-callout="caution"]::after{content:"🔥";color:#d63031}.theme-light .callout[data-callout="success"],.theme-light .callout[data-callout="done"]{background-color:rgba(85, 239, 196, 0.15) !important}.theme-light .callout[data-callout="success"] .callout-title{color:#00b894 !important}.theme-light .callout[data-callout="success"]:hover{background-color:rgba(85, 239, 196, 0.25) !important}.theme-light .callout[data-callout="success"]::after{content:"🎉";color:#00b894}.theme-light .callout[data-callout="example"]{background-color:rgba(162, 155, 254, 0.15) !important}.theme-light .callout[data-callout="example"] .callout-title{color:#6c5ce7 !important}.theme-light .callout[data-callout="example"]:hover{background-color:rgba(162, 155, 254, 0.25) !important}.theme-light .callout[data-callout="example"]::after{content:"🧩";color:#6c5ce7}.theme-light .callout[data-callout="quote"]{background-color:rgba(178, 190, 195, 0.15) !important}.theme-light .callout[data-callout="quote"] .callout-title{color:#636e72 !important}.theme-light .callout[data-callout="quote"]:hover{background-color:rgba(178, 190, 195, 0.25) !important}.theme-light .callout[data-callout="quote"]::after{content:"💬";color:#636e72}.theme-light .callout[data-callout="danger"],.theme-light .callout[data-callout="error"]{background-color:rgba(214, 48, 49, 0.15) !important;border-left-color:#d63031 !important}.theme-light .callout[data-callout="danger"] .callout-title,.theme-light .callout[data-callout="error"] .callout-title{color:#d63031 !important}.theme-light .callout[data-callout="danger"]:hover,.theme-light .callout[data-callout="error"]:hover{background-color:rgba(214, 48, 49, 0.2) !important}.theme-light .callout[data-callout="danger"]::after{content:"⚡";color:#d63031}.theme-light .callout[data-callout="error"]::after{content:"❌";color:#d63031}.theme-light .callout[data-callout="bug"]::after{content:"🐛";color:#d63031}.theme-light .callout[data-callout="failure"],.theme-light .callout[data-callout="missing"]{background-color:rgba(45, 52, 54, 0.05) !important}.theme-light .callout[data-callout="failure"] .callout-title{color:#c0392b !important}.theme-light .callout[data-callout="failure"]:hover{background-color:rgba(45, 52, 54, 0.1) !important}.theme-light .callout[data-callout="failure"]::after{content:"📉";color:#c0392b}.theme-light .callout[data-callout="question"],.theme-light .callout[data-callout="faq"],.theme-light .callout[data-callout="help"]{background-color:rgba(253, 203, 110, 0.15) !important}.theme-light .callout[data-callout="question"] .callout-title{color:#f39c12 !important}.theme-light .callout[data-callout="question"]:hover{background-color:rgba(253, 203, 110, 0.25) !important}.theme-light .callout[data-callout="question"]::after{content:"❓";color:#f39c12}.theme-light .callout[data-callout="abstract"],.theme-light .callout[data-callout="summary"],.theme-light .callout[data-callout="tldr"]{background-color:rgba(129, 236, 236, 0.2) !important}.theme-light .callout[data-callout="abstract"] .callout-title{color:#00cec9 !important}.theme-light .callout[data-callout="abstract"]:hover{background-color:rgba(129, 236, 236, 0.3) !important}.theme-light .callout[data-callout="abstract"]::after{content:"📑";color:#00cec9}.theme-dark .callout{background-color:rgba(255, 255, 255, 0.03) !important;border:1px solid rgba(255, 255, 255, 0.05) !important}.theme-dark .callout-title{background-color:rgba(255, 255, 255, 0.08) !important;border:1px solid rgba(255, 255, 255, 0.1) !important;color:var(--text-normal) !important}.theme-dark .callout[data-callout="note"]{border-color:rgba(189, 147, 249, 0.3) !important;background-color:rgba(189, 147, 249, 0.1) !important}.theme-dark .callout[data-callout="note"] .callout-title{color:#bd93f9 !important}.theme-dark .callout[data-callout="note"]:hover{background-color:rgba(189, 147, 249, 0.2) !important}.theme-dark .callout[data-callout="note"]::after{content:"📝";color:#bd93f9}.theme-dark .callout[data-callout="tip"]{border-color:rgba(139, 233, 253, 0.3) !important;background-color:rgba(139, 233, 253, 0.1) !important}.theme-dark .callout[data-callout="tip"] .callout-title{color:#8be9fd !important}.theme-dark .callout[data-callout="tip"]:hover{background-color:rgba(139, 233, 253, 0.2) !important}.theme-dark .callout[data-callout="tip"]::after{content:"💡";color:#8be9fd}.theme-dark .callout[data-callout="warning"]{border-color:rgba(255, 184, 108, 0.3) !important;background-color:rgba(255, 184, 108, 0.1) !important}.theme-dark .callout[data-callout="warning"] .callout-title{color:#ffb86c !important}.theme-dark .callout[data-callout="warning"]:hover{background-color:rgba(255, 184, 108, 0.2) !important}.theme-dark .callout[data-callout="warning"]::after{content:"⚠️";color:#ffb86c}.theme-dark .callout[data-callout="important"]{border-color:rgba(255, 85, 85, 0.3) !important;background-color:rgba(255, 85, 85, 0.1) !important}.theme-dark .callout[data-callout="important"] .callout-title{color:#ff5555 !important}.theme-dark .callout[data-callout="important"]:hover{background-color:rgba(255, 85, 85, 0.2) !important}.theme-dark .callout[data-callout="important"]::after{content:"🔥";color:#ff5555}.theme-dark .callout[data-callout="info"]{border-color:rgba(116, 192, 252, 0.3) !important;background-color:rgba(116, 192, 252, 0.1) !important}.theme-dark .callout[data-callout="info"] .callout-title{color:#74c0fc !important}.theme-dark .callout[data-callout="info"]::after{content:"ℹ️";color:#74c0fc}.theme-dark .callout[data-callout="todo"]{border-color:rgba(80, 250, 123, 0.3) !important;background-color:rgba(80, 250, 123, 0.1) !important}.theme-dark .callout[data-callout="todo"] .callout-title{color:#50fa7b !important}.theme-dark .callout[data-callout="todo"]::after{content:"✅";color:#50fa7b}.theme-dark .callout[data-callout="success"],.theme-dark .callout[data-callout="done"]{border-color:rgba(85, 239, 196, 0.3) !important;background-color:rgba(85, 239, 196, 0.1) !important}.theme-dark .callout[data-callout="success"] .callout-title{color:#55efc4 !important}.theme-dark .callout[data-callout="success"]:hover{background-color:rgba(85, 239, 196, 0.15) !important}.theme-dark .callout[data-callout="success"]::after{content:"🎉";color:#55efc4}.theme-dark .callout[data-callout="question"],.theme-dark .callout[data-callout="faq"],.theme-dark .callout[data-callout="help"]{border-color:rgba(241, 250, 140, 0.3) !important;background-color:rgba(241, 250, 140, 0.1) !important}.theme-dark .callout[data-callout="question"] .callout-title{color:#f1fa8c !important}.theme-dark .callout[data-callout="question"]:hover{background-color:rgba(241, 250, 140, 0.15) !important}.theme-dark .callout[data-callout="question"]::after{content:"❓";color:#f1fa8c}.theme-dark .callout[data-callout="example"]{border-color:rgba(255, 121, 198, 0.3) !important;background-color:rgba(255, 121, 198, 0.1) !important}.theme-dark .callout[data-callout="example"] .callout-title{color:#ff79c6 !important}.theme-dark .callout[data-callout="example"]:hover{background-color:rgba(255, 121, 198, 0.15) !important}.theme-dark .callout[data-callout="example"]::after{content:"🧩";color:#ff79c6}.theme-dark .callout[data-callout="quote"]{border-color:rgba(223, 230, 233, 0.2) !important;background-color:rgba(223, 230, 233, 0.05) !important}.theme-dark .callout[data-callout="quote"] .callout-title{color:#dfe6e9 !important}.theme-dark .callout[data-callout="quote"]::after{content:"💬";color:#dfe6e9}.theme-dark .callout[data-callout="danger"],.theme-dark .callout[data-callout="error"]{border-color:rgba(255, 85, 85, 0.4) !important;background-color:rgba(255, 85, 85, 0.1) !important;box-shadow:0 0 10px rgba(255, 85, 85, 0.1)}.theme-dark .callout[data-callout="danger"] .callout-title,.theme-dark .callout[data-callout="error"] .callout-title{color:#ff5555 !important}.theme-dark .callout[data-callout="danger"]::after{content:"⚡";color:#ff5555}.theme-dark .callout[data-callout="error"]::after{content:"❌";color:#ff5555}*/ .theme-dark .callout[data-callout="bug"]{border-color:rgba(255, 85, 85, 0.4) !important;background-color:rgba(255, 85, 85, 0.1) !important}.theme-dark .callout[data-callout="bug"] .callout-title{color:#ff5555 !important}.theme-dark .callout[data-callout="bug"]::after{content:"🐛";color:#ff5555}.theme-dark .callout[data-callout="failure"],.theme-dark .callout[data-callout="missing"]{border-color:rgba(179, 57, 57, 0.3) !important;background-color:rgba(0, 0, 0, 0.2) !important}.theme-dark .callout[data-callout="failure"] .callout-title{color:#fab1a0 !important}.theme-dark .callout[data-callout="failure"]::after{content:"📉";color:#fab1a0}.theme-dark .callout[data-callout="abstract"],.theme-dark .callout[data-callout="summary"]{border-color:rgba(129, 236, 236, 0.3) !important;background-color:rgba(129, 236, 236, 0.1) !important}.theme-dark .callout[data-callout="abstract"] .callout-title{color:#81ecec !important}.theme-dark .callout[data-callout="abstract"]::after{content:"📑";color:#81ecec}.markdown-source-view.mod-cm6 .cm-embed-block:not(.cm-table-widget, .cm-lang-base):hover{box-shadow:none}.markdown-preview-view :not(pre)>code,.markdown-source-view.mod-cm6 .cm-inline-code:not(.cm-formatting){font-family:var(--font-monospace) !important;letter-spacing:0.5px;background-color:color-mix(in srgb, var(--primary-color), transparent 90%);color:var(--primary-color) !important;border:1px solid color-mix(in srgb, var(--primary-color), transparent 85%);padding:2px 6px !important;margin:0 2px;border-radius:6px;vertical-align:middle;transition:all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);-webkit-box-decoration-break:clone;box-decoration-break:clone}.markdown-preview-view :not(pre)>code:hover{background-color:var(--primary-color) !important;color:#fff !important;border-color:var(--primary-color);box-shadow:0 0 15px color-mix(in srgb, var(--primary-color), transparent 60%);transform:scale(1.05);text-decoration:none !important;-webkit-text-fill-color:#fff !important;position:relative;z-index:1}.markdown-source-view.mod-cm6 .cm-formatting-code{color:var(--primary-color) !important;opacity:0.4;font-family:var(--font-monospace);font-weight:bold}.markdown-preview-view kbd,.markdown-source-view.mod-cm6 .cm-kbd,.markdown-source-view.mod-cm6 kbd{font-family:var(--font-monospace), "CascadiaCode", Consolas, monospace;font-size:0.9em;font-weight:600;line-height:1;text-align:center;display:inline-block;min-width:1.6em;padding:3px 6px;margin:0 4px;border-radius:6px;vertical-align:middle;transition:all 0.15s cubic-bezier(0.25, 0.8, 0.25, 1);text-shadow:none;cursor:default}body.theme-dark .markdown-preview-view kbd,body.theme-dark .markdown-source-view.mod-cm6 .cm-kbd,body.theme-dark .markdown-source-view.mod-cm6 kbd{background-color:#333;color:var(--text-color);border:1px solid #444;border-top-color:#555;border-bottom-color:#222;box-shadow:0 4px 0 #222, 0 5px 5px rgba(0, 0, 0, 0.4)}body.theme-dark .markdown-preview-view kbd:hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-kbd:hover,body.theme-dark .markdown-source-view.mod-cm6 kbd:hover{transform:translateY(2px);box-shadow:0 2px 0 #222, 0 3px 3px rgba(0, 0, 0, 0.4);color:var(--primary-color);border-color:var(--primary-color)}body.theme-light .markdown-preview-view kbd,body.theme-light .markdown-source-view.mod-cm6 .cm-kbd,body.theme-light .markdown-source-view.mod-cm6 kbd{background-color:#fff;color:var(--primary-color);border:1px solid var(--primary-color);border-bottom-width:3px;box-shadow:0 2px 4px color-mix(in srgb, var(--primary-color), transparent 85%)}body.theme-light .markdown-preview-view kbd:hover,body.theme-light .markdown-source-view.mod-cm6 .cm-kbd:hover,body.theme-light .markdown-source-view.mod-cm6 kbd:hover{transform:translateY(2px);border-bottom-width:1px;background-color:color-mix(in srgb, var(--primary-color), transparent 90%);box-shadow:none}.mermaid{display:block !important;width:100% !important;overflow-x:auto !important;overflow-y:hidden;margin:1em 0;padding-bottom:8px;text-align:center;background-color:transparent !important}.mermaid .node rect,.mermaid .node circle,.mermaid .node ellipse,.mermaid .node path{fill:color-mix(in srgb, var(--primary-color), transparent 90%) !important;stroke:var(--primary-color) !important;stroke-width:1.5px !important;opacity:1 !important}.mermaid .node polygon{fill:color-mix(in srgb, var(--secondary-color), transparent 85%) !important;stroke:var(--secondary-color) !important;stroke-width:1.5px !important}.mermaid .label,.mermaid foreignObject,.mermaid foreignObject div,.mermaid foreignObject span,.mermaid foreignObject p,.mermaid span.nodeLabel{color:var(--mermaid-text-color) !important;fill:#ffffff !important;background-color:transparent !important;background:none !important;border:none !important;box-shadow:none !important;font-size:12px !important;line-height:1.5 !important;font-weight:500 !important}.mermaid foreignObject{overflow:visible !important}.mermaid .node .label,.mermaid .label{stroke:none !important}.mermaid .edgePath .path,.mermaid .flowchart-link{stroke:#999 !important;stroke-width:1.5px !important;opacity:1 !important}.mermaid .marker path,.mermaid marker path{fill:#e0e0e0 !important;stroke:#e0e0e0 !important}.mermaid .edgeLabel .label rect{fill:#2e2e2e !important;opacity:1 !important;rx:4px}.mermaid .edgeLabel .label{background-color:#2e2e2e !important}.mermaid::-webkit-scrollbar{height:6px}.mermaid::-webkit-scrollbar-track{background:rgba(255, 255, 255, 0.05);border-radius:3px}.mermaid::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:3px}.mermaid::-webkit-scrollbar-thumb:hover{background:var(--secondary-color)}.community-modal-info{--h2-color:var(--primary-color)}.nav-file-tag{line-height:1rem}.modal{background-color:var(--background-primary);border-radius:16px;border:1px solid var(--border-color);box-shadow:0 20px 60px -10px rgba(0, 0, 0, 0.4);overflow:auto;max-width:1100px;transition:transform 0.2s ease, opacity 0.2s ease}.theme-dark .modal{background-color:rgba(20, 20, 25, 0.85);backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);border:1px solid rgba(255, 255, 255, 0.08);box-shadow:0 0 0 1px rgba(0, 0, 0, 0.2), 0 30px 80px -10px rgba(0, 0, 0, 0.6)}.theme-light .modal{background-color:rgba(255, 255, 255, 0.85);backdrop-filter:blur(20px) saturate(120%);-webkit-backdrop-filter:blur(20px) saturate(120%);border:1px solid rgba(0, 0, 0, 0.05);box-shadow:0 10px 40px -5px rgba(0, 0, 0, 0.1)}.modal-close-button{position:absolute;top:16px;right:16px;z-index:10;opacity:0.6;transition:all 0.2s ease}.modal-close-button:hover{opacity:1;background-color:var(--background-modifier-hover);color:var(--text-error);transform:rotate(90deg)}.vertical-tab-header{background-color:color-mix(in srgb, var(--background-secondary), transparent 60%);border-right:1px solid var(--border-color);width:230px;padding:15px 8px;flex-shrink:0}.vertical-tab-header-group-title{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:var(--text-muted);margin:2px 0 4px 10px}.vertical-tab-nav-item{display:flex;align-items:center;padding:5px 10px;margin-bottom:2px;border-radius:6px;cursor:pointer;font-size:14px;color:var(--text-normal);transition:all 0.2s ease;position:relative}.vertical-tab-nav-item-icon{margin-right:8px;color:var(--text-muted);display:flex;align-items:center;transition:color 0.2s ease}.vertical-tab-nav-item-icon svg{width:16px;height:16px;stroke-width:2px}.vertical-tab-nav-item:hover{background-color:var(--background-modifier-hover);color:var(--text-normal)}.vertical-tab-nav-item:hover .vertical-tab-nav-item-icon{color:var(--text-normal)}.vertical-tab-nav-item.is-active{background-color:var(--primary-color) !important;color:#ffffff !important;font-weight:600;box-shadow:0 2px 8px color-mix(in srgb, var(--primary-color), transparent 50%)}.vertical-tab-nav-item.is-active .vertical-tab-nav-item-icon{color:#ffffff !important;opacity:1}.workspace-leaf-content[data-type="bases"]{--bases-table-row-border-width:0px !important;--bases-table-column-border-width:0px !important;--table-border-width:0px !important;--bases-table-row-height:40px !important;--bases-table-font-size:14px !important;--bases-table-header-background:var(--background-primary);--bases-table-group-background:var(--background-primary)}.bases-toolbar{border-bottom:1px solid var(--border-color);padding:8px 16px;gap:12px}.bases-toolbar .text-icon-button{background-color:transparent;border:1px solid transparent;border-radius:8px;padding:4px 12px;color:var(--text-muted);font-size:13px;transition:all 0.2s ease;box-shadow:none !important}.bases-toolbar .text-icon-button:hover,.bases-toolbar .text-icon-button.is-active{background-color:var(--background-modifier-hover);color:var(--text-normal)}.bases-toolbar .text-button-icon svg{width:16px;height:16px;opacity:0.8}.bases-thead{background-color:var(--background-primary) !important;border-bottom:2px solid var(--background-modifier-border);box-shadow:none !important;z-index:10}.bases-table-header{color:var(--text-muted);font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;padding-left:12px}.bases-tr{box-shadow:none !important;border-bottom:1px solid transparent;transition:all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);cursor:pointer;margin:0 4px;width:calc(100% - 8px) !important;border-radius:8px}.bases-tr:hover{background-color:color-mix(in srgb, var(--primary-color), transparent 88%) !important;box-shadow:0 2px 8px rgba(0, 0, 0, 0.05), inset 0 0 0 1px color-mix(in srgb, var(--primary-color), transparent 90%) !important;border-bottom-color:transparent;transform:scale(1.005);z-index:10}.bases-tr:hover .bases-rendered-value{color:var(--text-normal) !important}.bases-tr:hover .internal-link{color:var(--primary-color) !important;text-decoration:none !important}.bases-tr.is-selected{background-color:color-mix(in srgb, var(--primary-color), transparent 80%) !important;box-shadow:inset 3px 0 0 var(--primary-color)}.bases-tr:hover .bases-td:first-child{border-top-left-radius:8px;border-bottom-left-radius:8px}.bases-tr:hover .bases-td:last-child{border-top-right-radius:8px;border-bottom-right-radius:8px}.bases-td{box-shadow:none !important;padding:0 12px !important;border-right:none !important}.bases-rendered-value{padding:0 !important;display:flex;align-items:center}.bases-rendered-value .internal-link{text-decoration:none !important;color:var(--text-normal) !important;font-weight:400;transition:color 0.2s ease}.bases-rendered-value .internal-link:hover{color:var(--primary-color) !important;text-decoration:underline !important;text-underline-offset:4px}.bases-table-header-icon{display:none}.bases-view{background-color:var(--background-primary)}.theme-light .bases-tr:not(:hover){border-bottom:1px solid rgba(0, 0, 0, 0.03)}.theme-dark .bases-tr:not(:hover){border-bottom:1px solid rgba(255, 255, 255, 0.03)}body{--scrollbar-bg:transparent;--scrollbar-thumb-bg:rgba(var(--mono-rgb-100), 0.1);--scrollbar-active-thumb-bg:rgba(var(--mono-rgb-100), 0.2)}body.theme-dark{--scrollbar-thumb-bg:rgba(255, 255, 255, 0.1);--scrollbar-active-thumb-bg:rgba(255, 255, 255, 0.2)}body.theme-light{--scrollbar-thumb-bg:rgba(0, 0, 0, 0.1);--scrollbar-active-thumb-bg:rgba(0, 0, 0, 0.2)}body:not(.restored-scrollbars) ::-webkit-scrollbar,body:not(.restored-scrollbars) .kanban-plugin__scroll-container::-webkit-scrollbar{width:8px;height:8px;background-color:var(--scrollbar-bg)}body:not(.restored-scrollbars) ::-webkit-scrollbar-thumb,body:not(.restored-scrollbars) .kanban-plugin__scroll-container::-webkit-scrollbar-thumb{background-clip:padding-box;border-radius:20px;border:2px solid transparent;min-height:45px;background-color:transparent}body:not(.restored-scrollbars) .mobile-toolbar-options-container::-webkit-scrollbar{display:none}body:not(.restored-scrollbars):not(.is-mobile) :hover::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-bg) !important}body:not(.restored-scrollbars) ::-webkit-scrollbar-thumb:hover,body:not(.restored-scrollbars) ::-webkit-scrollbar-thumb:active{background-color:var(--scrollbar-active-thumb-bg) !important}.workspace-leaf-content:is([data-type="surfing-view"], [data-type="graph"], [data-type="localgraph"]) ::-webkit-scrollbar,.scrollbar-hide ::-webkit-scrollbar{display:none}body.layout-cards:not(.is-mobile) .workspace-tabs:not(.mod-stacked) .workspace-leaf,body.layout-cards:not(.is-mobile) .workspace-tabs:not(.mod-stacked) .workspace-leaf-content,body.layout-cards:not(.is-mobile) .workspace-tabs:not(.mod-stacked) .view-header:not(.animate),body.layout-cards:not(.is-mobile) .workspace-tabs:not(.mod-stacked) .view-content:not(.vignette-radial, .vignette-linear, .animate, .ptm-fullscreen-writing-focus-element),body.layout-cards .mod-left-split .workspace-tab-header.has-active-menu,body.layout-cards .mod-right-split .workspace-tab-header.has-active-menu,body.layout-cards:not(.is-mobile) .workspace-tab-header-container,body.layout-cards .workspace>.workspace-split{background-color:transparent !important}body.layout-cards .workspace-tab-header-container,body.layout-cards .workspace-tabs.mod-top .workspace-tab-header-container,body.layout-cards .workspace-ribbon.mod-left:before{border-bottom:1px solid var(--background-card) !important}body.layout-cards .workspace-ribbon{border-right:transparent !important;background-color:var(--background-card)}body.layout-cards .sidebar-toggle-button,body.layout-cards .workspace-tabs.mod-top{background-color:var(--background-card)}body.layout-cards .workspace-ribbon.mod-left:before{background:transparent !important}body.layout-cards .workspace-leaf-resize-handle{--workspace-divider-color:transparent;border-color:var(--workspace-divider-color)}body.layout-cards .is-hidden-frameless:not(.is-fullscreen).is-focused .titlebar-button-container.mod-right{background-color:transparent}body.layout-cards:not(.is-mobile).mod-left-split .workspace-sidedock-vault-profile{border:0;padding:0;z-index:99}body.layout-cards .workspace-sidedock-vault-profile{border-top:transparent !important}body.layout-cards:not(.is-mobile) .workspace-split.mod-left-split .workspace-sidedock-vault-profile{background-color:var(--background-card)}body.layout-cards:not(.is-mobile).theme-light .workspace-tab-container{border-radius:20px 20px 10px 10px;border:1px solid color-mix(in srgb, var(--primary-color), transparent 80%);margin:8px 10px;background-color:color-mix(in srgb, var(--primary-color), #fff 96%)}body.layout-cards.theme-light .mod-vertical .workspace-tab-header-container{padding-left:20px}body.layout-cards.theme-light .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header-container-inner{align-items:center;justify-content:center;margin:0;margin-top:3px;width:100%;gap:10px;z-index:1}body.layout-cards.theme-light .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header{background:color-mix(in srgb, var(--primary-color), #fff 96%);border-radius:6px;border:1px solid rgba(255, 255, 255, 0.1);box-shadow:0 0 8px rgba(0, 0, 0, 0.15), inset 0 1px 1px rgba(255, 255, 255, 0.15);height:32px;padding:0 !important;transition:400ms, background-color 150ms ease-in-out}body.layout-cards.theme-light .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header.is-active{border:1px solid color-mix(in srgb, var(--primary-color), #fff 70%);box-shadow:0 0 8px color-mix(in srgb, var(--primary-color), transparent 75%), inset 0 1px 1px color-mix(in srgb, var(--primary-color), transparent 75%);background-color:var(--background-primary);font-weight:bold;flex-grow:1.67;max-width:240px}body.layout-cards.theme-light .mod-root:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header-inner{padding:0 4px 0 8px;transition:400ms, background-color 150ms ease-in-out, max-width 400ms}body.layout-cards .workspace-tab-header-container .workspace-tab-header::before,body.layout-cards .workspace-tab-header-container .workspace-tab-header::after,body.layout-cards .workspace .mod-root .workspace-tab-header-inner::after{display:none}body.layout-cards:not(.is-phone).theme-light .modal-container.mod-dim .modal,body.layout-cards:not(.is-phone).theme-light .status-bar{border-radius:var(--radius-xl);background:rgba(255, 255, 255, 0.6);border:1px solid rgba(255, 255, 255, 0.4);box-shadow:0 0 8px rgba(0, 0, 0, 0.05), inset 0 1px 1px rgba(255, 255, 255, 0.5);margin:0 5px 5px 5px;transform:translate(0, -5px)}body.layout-cards:not(.is-phone).theme-light .workspace-tabs{background:var(--background-card)}body.layout-cards:not(.is-mobile).theme-dark .workspace-tab-container{border-radius:20px 20px 10px 10px;border:1px solid rgba(255, 255, 255, 0.08);margin:8px 10px;background-color:var(--background-primary);box-shadow:0 2px 6px rgba(0, 0, 0, 0.4)}body.layout-cards.theme-dark .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header{background:rgba(255, 255, 255, 0.03);border-radius:6px;border:1px solid rgba(255, 255, 255, 0.05);box-shadow:none;height:32px;padding:0 !important;transition:400ms, background-color 150ms ease-in}body.layout-cards.theme-dark .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header.is-active{border:1px solid rgba(255, 255, 255, 0.1);box-shadow:0 2px 10px rgba(0, 0, 0, 0.3);background-color:var(--background-secondary);font-weight:bold;flex-grow:1.67;max-width:240px}body.layout-cards.theme-dark .workspace-tab-header.is-active .workspace-tab-header-inner-title{color:var(--text-normal)}body.layout-cards.theme-dark .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header-container-inner{align-items:center;justify-content:center;margin:0;margin-top:3px;width:100%;gap:10px}body.layout-cards:not(.is-phone).theme-dark .modal-container.mod-dim .modal,body.layout-cards:not(.is-phone).theme-dark .status-bar{border-radius:var(--radius-xl);background:rgba(30, 30, 30, 0.6);border:1px solid rgba(255, 255, 255, 0.08);box-shadow:0 0 20px rgba(0, 0, 0, 0.5);margin:0 5px 5px 5px;transform:translate(0, -5px)}.community-modal-meta{display:grid;grid-template-areas:"name name name name" "desc desc desc desc" "stats stats stats stats" "buttons buttons buttons buttons";grid-template-columns:2fr 2fr 2fr 1fr;gap:16px;margin-bottom:0 !important}.community-modal-info-name{grid-area:name;font-size:24px;font-weight:800;color:var(--primary-color);line-height:1.2;margin-bottom:4px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}.flair{font-size:11px;background-color:var(--background-secondary) !important;border:1px solid var(--border-color);color:var(--text-muted) !important;padding:2px 8px;border-radius:50px;text-transform:uppercase;font-weight:bold;letter-spacing:0.5px;top:-2px;position:relative}.flair.mod-pop{color:var(--secondary-color) !important;border-color:var(--secondary-color);background-color:color-mix(in srgb, var(--secondary-color), transparent 90%) !important}.community-modal-info-desc{grid-area:desc;font-size:15px;line-height:1.6;color:var(--text-normal);opacity:0.9;padding-bottom:20px;border-bottom:1px dashed var(--border-color);margin-bottom:8px}.community-modal-info-downloads,.community-modal-info-version,.community-modal-info-author,.community-modal-info-repo{display:flex;flex-direction:column;justify-content:center;gap:4px;padding:12px;background-color:var(--background-secondary);border-radius:8px;font-size:13px;color:var(--text-muted);margin:0 !important;min-width:0}.community-modal-info-downloads{grid-area:stats;grid-column:1}.community-modal-info-version{grid-area:stats;grid-column:2}.community-modal-info-author{grid-area:stats;grid-column:3}.community-modal-info-repo{grid-area:stats;grid-column:4}@media (max-width:700px){.community-modal-meta{grid-template-areas:"name" "desc" "stats-1" "stats-2" "stats-3" "stats-4" "buttons";grid-template-columns:1fr}.community-modal-info-downloads{grid-area:stats-1;grid-column:auto}.community-modal-info-version{grid-area:stats-2;grid-column:auto}.community-modal-info-author{grid-area:stats-3;grid-column:auto}.community-modal-info-repo{grid-area:stats-4;grid-column:auto}}.community-modal-info-downloads{color:var(--text-normal);font-weight:bold;border:1px solid color-mix(in srgb, var(--primary-color), transparent 80%);background-color:color-mix(in srgb, var(--primary-color), transparent 96%)}.community-modal-info-downloads::before{content:"DOWNLOADS";font-size:10px;font-weight:bold;color:var(--primary-color);opacity:0.7;margin-bottom:4px;letter-spacing:0.5px}.community-modal-info-downloads span{display:flex;align-items:center;gap:6px;font-size:16px}.community-modal-info-downloads svg{width:16px;height:16px;color:var(--primary-color)}.community-modal-info-version::before{content:"VERSION"}.community-modal-info-author::before{content:"AUTHOR"}.community-modal-info-repo::before{content:"REPOSITORY"}.community-modal-info-version::before,.community-modal-info-author::before,.community-modal-info-repo::before{font-size:10px;font-weight:bold;color:var(--text-muted);opacity:0.6;margin-bottom:2px;display:block}.community-modal-info-author a,.community-modal-info-repo a{color:var(--text-normal);text-decoration:none;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}.community-modal-info-author a:hover,.community-modal-info-repo a:hover{color:var(--primary-color);text-decoration:underline}.community-modal-button-container{grid-area:buttons;margin-top:20px;padding-top:20px;border-top:1px dashed var(--border-color);display:flex;gap:10px;flex-wrap:wrap}.community-modal-button-container button{flex:1;justify-content:center}.codeblock-customizer-line-number,.codeblock-customizer-line-number-specific{background:transparent}body.rainbow-folders .nav-folder{--nav-c-pink:#ff7096;--nav-c-cyan:#3db8bf;--nav-c-orange:#f59e0b;--nav-c-green:#11aa63;--nav-c-purple:#A06EB4;--nav-c-red:#aa1141;--nav-c-blue:#1D4E89;--folder-color:var(--text-muted);--nav-item-background-hover:color-mix(in srgb, var(--folder-color), transparent 95%);--background-modifier-active-hover:color-mix(in srgb, var(--primary-color), transparent 95%)}body.rainbow-folders .nav-files-container{--folder-color:var(--primary-color);--nav-item-background-hover:color-mix(in srgb, var(--primary-color), transparent 95%);--background-modifier-active-hover:color-mix(in srgb, var(--primary-color), transparent 90%)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+1){--folder-color:var(--nav-c-pink)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+2){--folder-color:var(--nav-c-cyan)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+3){--folder-color:var(--nav-c-orange)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+4){--folder-color:var(--nav-c-green)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+5){--folder-color:var(--nav-c-purple)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+6){--folder-color:var(--nav-c-red)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+7){--folder-color:var(--nav-c-blue)}body.rainbow-folders .nav-files-container > div > .nav-folder{margin:0 0 8px 0 !important;padding:0px 0 !important;border-radius:0 8px 8px 0;border-left:4px solid var(--folder-color) !important;transition:background-color 0.2s ease}body.rainbow-folders .nav-folder .nav-folder{border-left:none !important;background-color:transparent !important;margin:0 !important;padding:0 !important;border-radius:0}body.rainbow-folders .nav-folder.is-collapsed{padding-bottom:0 !important}body.rainbow-folders .nav-folder-title{padding:6px 8px !important;margin:1px 0 !important;border-radius:6px;font-weight:500;color:var(--folder-color);display:flex;align-items:center}body.rainbow-folders .nav-folder .nav-folder .nav-folder-title-content{opacity:0.9}body.rainbow-folders .nav-folder-title:hover{background-color:var(--background-modifier-hover)}body.rainbow-folders .nav-folder-collapse-indicator,body.rainbow-folders .nav-folder .collapse-icon{display:none !important}body.rainbow-folders .nav-folder-children{margin-left:14px !important;padding-left:10px !important;border-left:1px solid color-mix(in srgb, var(--folder-color), transparent 70%)}body.rainbow-folders .nav-folder:hover > .nav-folder-children{border-left-color:color-mix(in srgb, var(--folder-color), transparent 40%)}body.rainbow-folders .nav-folder-title-content::before,body.rainbow-folders .nav-file-title-content::before{content:"";display:inline-block;width:16px;height:16px;margin-right:8px;vertical-align:text-bottom;background-color:currentColor;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform 0.2s ease, opacity 0.2s ease}body.rainbow-folders .nav-file-title-content::before{width:14px;height:14px;opacity:0.6}body.rainbow-folders .nav-file-title:hover .nav-file-title-content::before{opacity:0.9}body.rainbow-folders .nav-folder-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z'/%3E%3C/svg%3E");opacity:0.8}body.rainbow-folders .nav-folder:not(.is-collapsed) > .nav-folder-title .nav-folder-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");opacity:1}body.rainbow-folders .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E")}body.rainbow-folders .nav-file-title[data-path$=".png" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".jpg" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".jpeg" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".gif" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".svg" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".webp" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E")}body.rainbow-folders .nav-file-title[data-path$=".canvas" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='7' height='9' x='3' y='3' rx='1'/%3E%3Crect width='7' height='5' x='14' y='3' rx='1'/%3E%3Crect width='7' height='9' x='14' y='12' rx='1'/%3E%3Crect width='7' height='5' x='3' y='16' rx='1'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='7' height='9' x='3' y='3' rx='1'/%3E%3Crect width='7' height='5' x='14' y='3' rx='1'/%3E%3Crect width='7' height='9' x='14' y='12' rx='1'/%3E%3Crect width='7' height='5' x='3' y='16' rx='1'/%3E%3C/svg%3E")}body.rainbow-folders .nav-file-title[data-path$=".base" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E")}body.theme-light.rainbow-folders .nav-files-container > div > .nav-folder{background-color:color-mix(in srgb, var(--folder-color), transparent 96%);border-top:1px solid color-mix(in srgb, var(--folder-color), transparent 92%);border-bottom:1px solid color-mix(in srgb, var(--folder-color), transparent 92%);border-right:1px solid color-mix(in srgb, var(--folder-color), transparent 92%)}body.theme-light.rainbow-folders .nav-files-container > div > .nav-folder:hover{background-color:color-mix(in srgb, var(--folder-color), transparent 92%)}body.theme-dark.rainbow-folders .nav-files-container > div > .nav-folder{background-color:color-mix(in srgb, var(--folder-color), transparent 96%);border-top:1px solid color-mix(in srgb, var(--folder-color), transparent 95%);border-bottom:1px solid color-mix(in srgb, var(--folder-color), transparent 95%);border-right:1px solid color-mix(in srgb, var(--folder-color), transparent 95%)}body.theme-dark.rainbow-folders .nav-files-container > div > .nav-folder:hover{background-color:color-mix(in srgb, var(--folder-color), transparent 92%)}body.rainbow-folders .nav-file-title{padding:4px 8px !important;border-radius:6px;color:var(--text-muted)}body.rainbow-folders .nav-file-title:hover{background-color:var(--background-modifier-hover);color:var(--text-normal)}body.rainbow-folders .nav-file-title.is-active{background-color:var(--background-modifier-active-hover);color:var(--primary-color);font-weight:600}body.rainbow-folders .nav-file-title.is-active .nav-file-title-content::before{background-color:var(--primary-color);opacity:1}@media (hover:hover){body.rainbow-folders:not(.is-grabbing) .tree-item-self.is-clickable:hover{color:var(--folder-color);font-weight:bolder}}.nav-files-container > div > .nav-folder{margin:0 0 8px 0 !important;padding:0 !important;border-left:3px solid var(--folder-color) !important;border-radius:0 6px 6px 0;transition:background-color 0.2s ease}.nav-folder .nav-folder{border-left:none !important;background-color:transparent !important;margin:0 !important;padding:0 !important;border-radius:0}.nav-folder.is-collapsed{padding-bottom:0 !important}.nav-folder-title{padding:4px 6px !important;margin:1px 0 !important;border-radius:4px;font-weight:500;color:var(--folder-color);display:flex;align-items:center}.nav-files-container > div > .nav-folder > .nav-folder-title{padding-left:8px !important}.nav-folder .nav-folder .nav-folder-title-content{opacity:0.9}.nav-folder-title:hover{background-color:var(--background-modifier-hover)}.nav-folder-collapse-indicator,.nav-folder .collapse-icon{display:none !important}.nav-folder-title-content::before,.nav-file-title-content::before{content:"";display:inline-block;width:16px;height:16px;margin-right:8px;vertical-align:text-bottom;background-color:currentColor;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform 0.2s ease, opacity 0.2s ease}.nav-file-title-content::before{width:14px;height:14px;opacity:0.6}.nav-file-title:hover .nav-file-title-content::before{opacity:0.9}.nav-folder-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z'/%3E%3C/svg%3E");opacity:0.8}.nav-folder:not(.is-collapsed) > .nav-folder-title .nav-folder-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");opacity:1}.nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E")}.nav-file-title[data-path$=".png" i] .nav-file-title-content::before,.nav-file-title[data-path$=".jpg" i] .nav-file-title-content::before,.nav-file-title[data-path$=".jpeg" i] .nav-file-title-content::before,.nav-file-title[data-path$=".gif" i] .nav-file-title-content::before,.nav-file-title[data-path$=".svg" i] .nav-file-title-content::before,.nav-file-title[data-path$=".webp" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E")}.nav-file-title[data-path$=".canvas" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='7' height='9' x='3' y='3' rx='1'/%3E%3Crect width='7' height='5' x='14' y='3' rx='1'/%3E%3Crect width='7' height='9' x='14' y='12' rx='1'/%3E%3Crect width='7' height='5' x='3' y='16' rx='1'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='7' height='9' x='3' y='3' rx='1'/%3E%3Crect width='7' height='5' x='14' y='3' rx='1'/%3E%3Crect width='7' height='9' x='14' y='12' rx='1'/%3E%3Crect width='7' height='5' x='3' y='16' rx='1'/%3E%3C/svg%3E")}.nav-file-title[data-path$=".base" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E")}.nav-file-title{padding:4px 8px !important;border-radius:6px;color:var(--text-muted)}.nav-file-title:hover{background-color:var(--background-modifier-hover);color:var(--text-normal)}.nav-file-title.is-active{background-color:var(--background-modifier-active-hover);color:var(--primary-color);font-weight:600}.nav-file-title.is-active .nav-file-title-content::before{background-color:var(--primary-color);opacity:1}@media (hover:hover){body:not(.is-grabbing) .tree-item-self.is-clickable:hover{color:var(--folder-color);font-weight:bolder}}.codeblock-customizer-active-line-highlight .cm-active, .codeblock-customizer-active-line-highlight-editor .cm-active{background-color:color-mix(in srgb, var(--primary-color) , transparent 95%)!important} \ No newline at end of file +:root{--h3-icon-shape:url("data:image/svg+xml;utf8,");--h4-icon-shape:url("data:image/svg+xml;utf8,");--h5-icon-shape:url("data:image/svg+xml;utf8,");--h6-icon-shape:url("data:image/svg+xml;utf8,");--list-spacing:0.075em}body{--blockquote-line-height:1.6;--table-line-height:1.8;--letter-spacing:1px;--code-size:0.95rem;--code-white-space:pre;--code-radius:8px;--checkbox-size:1.25rem;--checkmark-color:#ffffff;--table-border-radius:8px;--text-faint:color-mix(in srgb, var(--primary-color), transparent 20%);--link-external-decoration-hover:none;--titlebar-background:transparent;--titlebar-background-focused:transparent;--he-title-bar-inactive-pinned-bg:color-mix(in srgb, var(--primary-color), #fff 20%);--h1-line-height:1.2;--h2-line-height:1.5;--h3-line-height:1.5;--h4-line-height:1.4;--h5-line-height:1.4;--h6-line-height:1.4;--file-line-width:900px;--h1-spacing-scale-start:1.5;--h1-spacing-scale-end:1.5;--h2-spacing-scale-start:1.5;--h2-spacing-scale-end:1.5;--h3-spacing-scale-start:1.5;--h3-spacing-scale-end:1.5;--h4-spacing-scale-start:1.5;--h4-spacing-scale-end:1.5;--h5-spacing-scale-start:1.5;--h5-spacing-scale-end:1.5;--h6-spacing-scale-start:1.5;--h6-spacing-scale-end:1.5;--heading-spacing:0.5rem;--h3-spacing-scale:1.6;--h2-spacing-scale:0.2;--word-spacing:2px;--h1-letter-spacing:-0.015em;--h2-letter-spacing:-0.011em;--h3-letter-spacing:-0.008em;--h4-letter-spacing:-0.005em;--h5-letter-spacing:-0.002em;--h6-letter-spacing:0em;--h1-line-height:1.2;--h2-line-height:1.2;--h3-line-height:1.3;--h4-line-height:1.4;--h5-line-height:1.4;--h6-line-height:1.4;--h1-size:1.618em;--h2-size:1.462em;--h3-size:1.318em;--h4-size:1.2em;--h5-size:1.2em;--h6-size:1.2em;.token.keyword, .token.tag, .token.selector{color:var(--code-keyword);font-weight:bold}.token.function, .token.class-name{color:var(--code-function)}.token.string, .token.attr-value{color:var(--code-string)}.token.comment{color:var(--code-comment);font-style:italic}.token.number, .token.boolean{color:var(--code-value)}.token.operator, .token.variable{color:var(--code-operator)}.token.property, .token.attr-name{color:var(--code-property)}.token.punctuation{color:var(--code-punctuation)}.token.important, .token.bold{font-weight:bold;color:var(--code-important, var(--code-keyword))}.token.italic{font-style:italic}.token.url{color:var(--code-string);text-decoration:underline}}body.theme-dark.theme-dark-vampire,body.theme-dark:not(.theme-dark-abyss):not(.theme-dark-radiation){--bg-color:#282a36;--text-color:#f8f8f2;--text-color-secondary:#d0d0d0;--border-color:#44475a;--primary-color:#ff5555;--secondary-color:#bd93f9;--accent-color:#8be9fd;--glow-color:rgba(255, 85, 85, 0.6);--hover-background-color:rgb(255, 85, 85);--select-text-bg-color:rgba(255, 16, 16, 0.466);--link-hover-color:#ff92d0;--h1-underline-color:var(--primary-color);--h2-bg-image:radial-gradient(ellipse at center bottom, rgba(255, 85, 85, 0.15), transparent 70%);--h2-bg-image-hover:radial-gradient(ellipse at center bottom, rgba(255, 85, 85, 0.25), transparent 60%);--code-block-bg:#282a36;--code-keyword:#ff79c6;--code-function:#50fa7b;--code-string:#f1fa8c;--code-comment:#6272a4;--code-property:#66d9ef;--code-value:#bd93f9;--code-punctuation:#f8f8f2;--code-tag:#ff79c6;--code-operator:#ff79c6;--code-important:#ff79c6}body.theme-dark.theme-dark-abyss{--bg-color:#0f111a;--text-color:#d6deeb;--text-color-secondary:#7e8c9f;--border-color:#1f2233;--primary-color:#00b7c0;--secondary-color:#2e8bd6;--accent-color:#d500f9;--glow-color:rgba(0, 243, 255, 0.5);--hover-background-color:#00f3ff;--select-text-bg-color:rgba(7, 243, 255, 0.445);--link-hover-color:#82aaff;--h1-underline-color:var(--primary-color);--h2-bg-image:radial-gradient(ellipse at center bottom, rgba(0, 243, 255, 0.15), transparent 70%);--h2-bg-image-hover:radial-gradient(ellipse at center bottom, rgba(0, 243, 255, 0.25), transparent 60%);--code-block-bg:#0f111a;--code-keyword:#c792ea;--code-function:#82aaff;--code-string:#ecc48d;--code-comment:#637777;--code-property:#80cbc4;--code-value:#f78c6c;--code-punctuation:#d6deeb;--code-tag:#ff5370;--code-operator:#89ddff;--code-important:#c792ea}body.theme-dark.theme-dark-radiation{--bg-color:#1b1d1b;--text-color:#e6e6e6;--text-color-secondary:#99a699;--border-color:#333933;--primary-color:#4cd964;--secondary-color:#ffc107;--accent-color:#29b6f6;--glow-color:rgba(76, 217, 100, 0.4);--hover-background-color:#4cd964;--select-text-bg-color:rgba(76, 217, 100, 0.3);--link-hover-color:#a5d6a7;--h1-underline-color:var(--primary-color);--h2-bg-image:radial-gradient(ellipse at center bottom, rgba(76, 217, 100, 0.1), transparent 70%);--h2-bg-image-hover:radial-gradient(ellipse at center bottom, rgba(76, 217, 100, 0.2), transparent 60%);--code-block-bg:#1b1d1b;--code-keyword:#ffcb6b;--code-function:#4cd964;--code-string:#c3e88d;--code-comment:#546e7a;--code-property:#4cd964;--code-value:#f78c6c;--code-punctuation:#e6e6e6;--code-tag:#ff5370;--code-operator:#89ddff;--code-important:#ffcb6b}body.theme-light.theme-light-sakura,body.theme-light:not(.theme-light-sky):not(.theme-light-forest):not(.theme-light-mint):not(.theme-light-mauve):not(.theme-light-golden):not(.theme-light-cherry):not(.theme-light-prussian){--primary-color:#ff7096;--secondary-color:#bd93f9;--bg-color:#fff7fa;--light-deep:#e91e63;--light-light:#ffb7cd;--light-lighter:#ffe3ec;--light-pale:#fff0f5;--text-color:#1c1719;--text-color-secondary:#3f3a3b;--link-hover-color:#d81b60;--select-text-bg-color:rgba(255, 112, 150, 0.3);--glow-color:rgba(255, 112, 150, 0.5);--border-color:color-mix(in srgb, var(--primary-color), transparent 60%);--h2-bg-gradient:linear-gradient(to right, var(--light-light), var(--primary-color), var(--light-light));--h2-shadow-color:rgba(61, 184, 211, 0.15);--h2-shadow-hover:rgba(61, 184, 211, 0.35);--text-bold:var(--light-deep);--code-normal:#546e7a;--code-string:#2e7d32;--code-comment:#b0bec5;--code-keyword:#d81b60;--code-function:#8e24aa;--code-value:#f57c00;--code-tag:#d81b60;--code-operator:#8e24aa;--code-property:#00897b;--code-punctuation:#78909c;--code-block-bg:#fff4f8;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 92%)}body.theme-light.theme-light-sky{--primary-color:#3498db;--secondary-color:#5296d5;--bg-color:#f4faff;--light-deep:#1a5276;--light-light:#85c1e9;--light-lighter:#aed6f1;--light-pale:#ebf5fb;--text-color:#080d12;--text-color-secondary:#0a1112;--link-hover-color:#2980b9;--select-text-bg-color:rgba(52, 152, 219, 0.25);--glow-color:rgba(52, 152, 219, 0.5);--code-block-bg:var(--light-pale);--border-color:color-mix(in srgb, var(--primary-color), transparent 60%);--h2-bg-gradient:linear-gradient(to right, var(--light-light), var(--primary-color), var(--light-light));--h2-shadow-color:rgba(52, 152, 219, 0.15);--h2-shadow-hover:rgba(52, 152, 219, 0.35);--text-bold:var(--light-deep);--code-normal:#24292e;--code-keyword:#d73a49;--code-function:#6f42c1;--code-string:#032f62;--code-value:#005cc5;--code-comment:#6a737d;--code-tag:#22863a;--code-operator:#d73a49;--code-property:#005cc5;--code-punctuation:#24292e;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-forest{--primary-color:#11aa63;--secondary-color:#14ae9c;--bg-color:#f2f9f5;--light-deep:#008145;--light-light:#43bd84;--light-lighter:#68eaad;--light-pale:#f9fffb;--text-color:#000000;--text-color-secondary:#5c7066;--link-hover-color:#009a52;--select-text-bg-color:rgba(17, 170, 99, 0.25);--glow-color:rgba(17, 170, 99, 0.5);--code-block-bg:var(--light-pale);--border-color:color-mix(in srgb, var(--primary-color), transparent 60%);--h2-bg-gradient:linear-gradient(to right, var(--light-light), var(--light-lighter), var(--light-light));--h2-shadow-color:rgba(17, 170, 99, 0.15);--h2-shadow-hover:rgba(17, 170, 99, 0.35);--text-bold:var(--light-deep);--code-normal:#383a42;--code-keyword:#a626a4;--code-function:#4078f2;--code-string:#50a14f;--code-value:#986801;--code-comment:#9ca0a4;--code-tag:#e45649;--code-operator:#0184bc;--code-property:#4078f2;--code-punctuation:#383a42;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-forest h2{text-shadow:0 1px 2px rgba(0, 0, 0, 0.1)}body.theme-light.theme-light-mint{--primary-color:#3db8bf;--secondary-color:#2acd9e;--bg-color:#f4fdff;--light-deep:#089ba3;--light-light:#7aeaf0;--light-lighter:#b2ebf2;--light-pale:#e0f7fa;--text-color:#263238;--text-color-secondary:#546e7a;--link-hover-color:#00838f;--select-text-bg-color:#7aeaf077;--glow-color:rgba(61, 184, 191, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #80F7C4, #3DB8D3, #80F7C4);--h2-shadow-color:rgba(61, 184, 191, 0.15);--h2-shadow-hover:rgba(61, 184, 191, 0.35);--text-bold:var(--light-deep);--code-normal:#37474f;--code-string:#00695c;--code-comment:#90a4ae;--code-keyword:#0097a7;--code-function:#0277bd;--code-value:#f57f17;--code-tag:#0097a7;--code-operator:#0277bd;--code-property:#00695c;--code-punctuation:#546e7a;--code-block-bg:#f0fcff;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-mauve{--primary-color:#A06EB4;--secondary-color:#6A3F7A;--bg-color:#FAFAFC;--light-deep:#6A3F7A;--light-light:#D4B6E0;--light-lighter:#F3E5F5;--light-pale:#F3E5F5;--text-color:#4A235A;--text-color-secondary:#6A3F7A;--link-hover-color:#ba68c8;--select-text-bg-color:#f0d7f966;--glow-color:rgba(160, 110, 180, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #D8B4E2, #A06EB4, #D8B4E2);--h2-shadow-color:rgba(160, 110, 180, 0.15);--h2-shadow-hover:rgba(160, 110, 180, 0.35);--text-bold:var(--light-deep);--code-background:#F2EFF9;--code-normal:#5E35B1;--code-normal:#4a148c;--code-string:#2e7d32;--code-comment:#9fa8da;--code-keyword:#ba68c8;--code-function:#7b1fa2;--code-value:#f57c00;--code-tag:#ba68c8;--code-operator:#7b1fa2;--code-punctuation:#6a1b9a;--code-block-bg:#fcfbfd;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-golden{--primary-color:#f59e0b;--secondary-color:#b45309;--bg-color:#fffbeb;--light-deep:#b45309;--light-light:#fbbf24;--light-lighter:#fef3c7;--light-pale:#fffbeb;--text-color:#78350f;--text-color-secondary:#92400e;--link-hover-color:#f59e0b;--select-text-bg-color:#f59e0b33;--glow-color:rgba(245, 158, 11, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #fcd34d, #f59e0b, #fcd34d);--h2-shadow-color:rgba(245, 158, 11, 0.15);--h2-shadow-hover:rgba(245, 158, 11, 0.35);--text-bold:var(--light-deep);--code-background:#fff7ed;--code-normal:#92400e;--code-normal:#5d4037;--code-string:#689f38;--code-comment:#a1887f;--code-keyword:#d84315;--code-function:#f57f17;--code-value:#e65100;--code-tag:#d84315;--code-operator:#f57f17;--code-punctuation:#8d6e63;--code-block-bg:#fffbf0;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-cherry{--primary-color:#aa1141;--secondary-color:#810000;--bg-color:#fffbfb;--light-deep:#9a0036;--light-light:#ffa6a6;--light-lighter:#fec2c2;--light-pale:#fffbfb;--text-color:#333333;--text-color-secondary:#870e0e;--link-hover-color:#d81b60;--select-text-bg-color:rgba(123, 123, 123, 0.507);--glow-color:rgba(170, 17, 65, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #b41919, #ea68b6, #b41919);--h2-shadow-color:rgba(170, 17, 65, 0.15);--h2-shadow-hover:rgba(170, 17, 65, 0.35);--text-bold:var(--light-deep);--code-background:rgb(177 108 108 / 2%);--code-normal:#9a0000;--code-normal:#4a0d18;--code-string:#2e7d32;--code-comment:#8d6e63;--code-keyword:#c2185b;--code-function:#d32f2f;--code-value:#e65100;--code-tag:#c2185b;--code-operator:#d32f2f;--code-punctuation:#870e0e;--code-block-bg:#fff5f7;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light.theme-light-prussian{--primary-color:#1D4E89;--secondary-color:#003153;--bg-color:#F0F6FA;--light-deep:#003153;--light-light:#6BA3CC;--light-lighter:#E1EDF5;--light-pale:#F0F6FA;--text-color:#003153;--text-color-secondary:#1D4E89;--link-hover-color:#2962ff;--select-text-bg-color:rgba(29, 78, 137, 0.2);--glow-color:rgba(29, 78, 137, 0.4);--border-color:color-mix(in srgb, var(--primary-color), transparent 75%);--h2-bg-gradient:linear-gradient(to right, #6BA3CC, #1D4E89, #6BA3CC);--h2-shadow-color:rgba(29, 78, 137, 0.15);--h2-shadow-hover:rgba(29, 78, 137, 0.35);--text-bold:var(--light-deep);--code-background:#EBF5FA;--code-normal:#0F3057;--code-normal:#37474f;--code-string:#2e7d32;--code-comment:#90a4ae;--code-keyword:#0277bd;--code-function:#006064;--code-value:#e65100;--code-tag:#0277bd;--code-operator:#006064;--code-punctuation:#455a64;--code-block-bg:#f5f9fc;--code-block-header-bg:color-mix(in srgb, var(--primary-color), transparent 94%)}body.theme-light{--glow-shadow-text:0 0 5px var(--glow-color);--glow-shadow-box:0 0 5px var(--glow-color);--background-primary:color-mix(in srgb, var(--bg-color), #fff 2%);--background-card:color-mix(in srgb, var(--primary-color), #FFF calc(var(--bg-mix-percent) * 1%));--background-primary-alt:color-mix(in srgb, var(--bg-color), #000 3%);--background-secondary:color-mix(in srgb, var(--bg-color), #fff 5%);--background-secondary-alt:color-mix(in srgb, var(--bg-color), #000 8%);--text-normal:var(--text-color);--text-muted:var(--text-color-secondary);--mermaid-text-color:var(--text-color);--text-accent:var(--primary-color);--text-accent-hover:var(--link-hover-color);--list-marker-color:var(--primary-color);--interactive-accent:var(--primary-color);--interactive-accent-hover:var(--link-hover-color);--text-selection:#dce3e9b6;--background-modifier-hover:rgba(0, 0, 0, 0.05);--background-modifier-active-hover:rgba(0, 0, 0, 0.1);--background-modifier-border:var(--border-color);--background-modifier-border-hover:var(--secondary-color);--background-modifier-error:#d32f2f;--background-modifier-success:#388e3c;--code-background:var(--code-block-bg);--code-normal:var(--text-color);--input-shadow:inset 0 0 0 1px var(--border-color);--input-shadow-hover:inset 0 0 0 1px var(--secondary-color);--checkbox-bg-unchecked:color-mix(in srgb, var(--primary-color), transparent 90%);--checkbox-border-unchecked:color-mix(in srgb, var(--primary-color), transparent 50%);--checkbox-bg-checked:var(--primary-color);--checkbox-shadow-checked:0 2px 5px color-mix(in srgb, var(--primary-color), transparent 60%);--table-bg:rgba(255, 255, 255, 0.4);--table-border-inner:rgba(0, 0, 0, 0.06);--table-row-hover-bg:rgba(0, 0, 0, 0.03);--table-th-bg:color-mix(in srgb, var(--primary-color), white 90%);--table-th-border:color-mix(in srgb, var(--primary-color), transparent 80%);--table-cell-hover-bg:color-mix(in srgb, var(--primary-color), white 80%);--table-cell-hover-text:var(--primary-color);--border-color:color-mix(in srgb, var(--primary-color), transparent 50%);--blockquote-background-color:color-mix(in srgb, var(--primary-color), white 96%);--setting-items-background:color-mix(in srgb, var(--light-lighter), transparent 94%);--indentation-guide-color:color-mix(in srgb, var(--primary-color), white 50%);--tag-background:color-mix(in srgb, var(--primary-color), white 85%);--tag-background-hover:color-mix(in srgb, var(--primary-color), white 75%);--tag-border-color:color-mix(in srgb, var(--primary-color), white 50%);--tag-border-color-hover:var(--primary-color);--h1-color:var(--h1-light-color, #000000);--h2-color:var(--h2-light-color, #000000);--h3-color:var(--h3-light-color, #000000);--h4-color:var(--h4-light-color, #000000);--h5-color:var(--h5-light-color, #000000);--h6-color:var(--h6-light-color, #000000);--ribbon-background-collapsed:var(--background-card)}body.theme-dark{--glow-shadow-text:0 0 8px var(--glow-color);--glow-shadow-box:0 0 8px var(--glow-color);--background-primary:var(--bg-color);--background-primary-alt:var(--bg-color);--background-secondary:color-mix(in srgb, var(--bg-color), #000 15%);--background-secondary-alt:color-mix(in srgb, var(--bg-color), #000 25%);--text-normal:var(--text-color);--text-muted:var(--text-color-secondary);--mermaid-text-color:#000;--text-accent:var(--primary-color);--text-accent-hover:var(--link-hover-color);--list-marker-color:var(--primary-color);--interactive-accent:var(--primary-color);--interactive-accent-hover:var(--link-hover-color);--text-selection:var(--select-text-bg-color);--background-modifier-hover:rgba(255, 255, 255, 0.05);--background-modifier-active-hover:rgba(255, 255, 255, 0.1);--background-modifier-border:var(--border-color);--background-modifier-border-hover:var(--secondary-color);--background-modifier-error:#ff5555;--background-modifier-success:#50fa7b;--code-background:var(--code-block-bg);--code-normal:var(--text-color);--checkbox-bg-unchecked:rgba(255, 255, 255, 0.05);--checkbox-border-unchecked:rgba(255, 255, 255, 0.3);--checkbox-bg-checked:color-mix(in srgb, var(--primary-color), transparent 80%);--checkbox-shadow-checked:0 0 8px var(--primary-color);--table-bg:rgba(255, 255, 255, 0.02);--table-border-inner:rgba(255, 255, 255, 0.05);--table-row-hover-bg:rgba(255, 255, 255, 0.03);--table-th-bg:color-mix(in srgb, var(--primary-color), transparent 95%);--table-th-border:color-mix(in srgb, var(--primary-color), transparent 85%);--table-cell-hover-bg:color-mix(in srgb, var(--primary-color), transparent 85%);--table-cell-hover-text:#fff;--setting-items-background:color-mix(in srgb, var(--primary-color), transparent 96%);--tag-background:color-mix(in srgb, var(--primary-color), transparent 85%);--tag-background-hover:color-mix(in srgb, var(--primary-color), transparent 75%);--tag-border-color:color-mix(in srgb, var(--primary-color), transparent 50%);--tag-border-color-hover:var(--primary-color);--h1-color:var(--h1-dark-color, #ffffff);--h2-color:var(--h2-dark-color, #ffffff);--h3-color:var(--h3-dark-color, #ffffff);--h4-color:var(--h4-dark-color, #ffffff);--h5-color:var(--h5-dark-color, #ffffff);--h6-color:var(--h6-dark-color, #ffffff)}body{--line-height-normal:2.2;--line-height-tight:1.3;--line-height-customize:var(--line-height-normal)}.markdown-preview-view,.markdown-source-view{letter-spacing:var(--letter-spacing);position:relative}.markdown-preview-view p,.markdown-preview-view li{color:var(--text-color-secondary);word-spacing:var(--word-spacing)}.markdown-preview-view,.markdown-source-view.mod-cm6 .cm-scroller{line-height:var(--line-height-customize)}.markdown-preview-view :is(.metadata-container, .frontmatter-container, .frontmatter),.markdown-source-view.mod-cm6 :is(.metadata-container, .frontmatter-container, .frontmatter){line-height:1.4}:is(.markdown-preview-view, .markdown-source-view.mod-cm6) .metadata-container :is( .metadata-content, .metadata-properties, .metadata-property, .metadata-property-key, .metadata-property-key-input, .metadata-property-value, .metadata-property-value-item, .metadata-property-value > *, .metadata-input, .metadata-input-text, .metadata-input-longtext, .metadata-input-number, .metadata-input-checkbox, .metadata-link, .multi-select-container, .multi-select-input, .multi-select-pill, .multi-select-pill-content){line-height:inherit}body .markdown-preview-view h1,body .markdown-source-view.mod-cm6 .HyperMD-header-1{color:var(--h1-color) !important}body .markdown-preview-view h2,body .markdown-source-view.mod-cm6 .HyperMD-header-2{color:var(--h2-color) !important}body .markdown-preview-view h3,body .markdown-source-view.mod-cm6 .HyperMD-header-3{color:var(--h3-color) !important}body .markdown-preview-view h4,body .markdown-source-view.mod-cm6 .HyperMD-header-4{color:var(--h4-color) !important}body .markdown-preview-view h5,body .markdown-source-view.mod-cm6 .HyperMD-header-5{color:var(--h5-color) !important}body .markdown-preview-view h6,body .markdown-source-view.mod-cm6 .HyperMD-header-6{color:var(--h6-color) !important}.markdown-preview-view h1,.markdown-preview-view h2,.markdown-preview-view h3,.markdown-preview-view h4,.markdown-preview-view h5,.markdown-preview-view h6,.markdown-source-view.mod-cm6 .HyperMD-header{color:var(--text-color);font-weight:bold;position:relative;transition:all 0.3s ease;margin-block-start:var(--heading-spacing);margin-block-end:var(--heading-spacing)}.markdown-preview-view h1{margin-block-start:calc(var(--heading-spacing)*var(--h1-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h1-spacing-scale-end))}.markdown-preview-view h2{margin-block-start:calc(var(--heading-spacing)*var(--h2-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h2-spacing-scale-end))}.markdown-preview-view h3{margin-block-start:calc(var(--heading-spacing)*var(--h3-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h3-spacing-scale-end))}.markdown-preview-view h4{margin-block-start:calc(var(--heading-spacing)*var(--h4-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h4-spacing-scale-end))}.markdown-preview-view h5{margin-block-start:calc(var(--heading-spacing)*var(--h5-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h5-spacing-scale-end))}.markdown-preview-view h6{margin-block-start:calc(var(--heading-spacing)*var(--h6-spacing-scale-start));margin-block-end:calc(var(--heading-spacing)*var(--h6-spacing-scale-end))}.markdown-source-view.mod-cm6 .HyperMD-header-1{padding-top:calc(var(--heading-spacing)*var(--h1-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h1-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-2{padding-top:calc(var(--heading-spacing)*var(--h2-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h2-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-3{padding-top:calc(var(--heading-spacing)*var(--h3-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h3-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-4{padding-top:calc(var(--heading-spacing)*var(--h4-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h4-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-5{padding-top:calc(var(--heading-spacing)*var(--h5-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h5-spacing-scale-end) - 0.25rem)}.markdown-source-view.mod-cm6 .HyperMD-header-6{padding-top:calc(var(--heading-spacing)*var(--h6-spacing-scale-start) - 0.25rem);padding-bottom:calc(var(--heading-spacing)*var(--h6-spacing-scale-end) - 0.25rem)}.theme-light .markdown-preview-view .heading-collapse-indicator{margin-inline-start:-47px !important}.theme-dark .markdown-preview-view .heading-collapse-indicator{margin-inline-start:-26px !important}.theme-light .markdown-preview-view h2 .heading-collapse-indicator{margin-inline-start:-19px !important}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2 .heading-collapse-indicator{margin-inline-start:-19px !important}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2 .heading-collapse-indicator{margin-inline-start:-48px !important}.theme-dark .markdown-preview-view h3 .heading-collapse-indicator,.theme-light .markdown-preview-view h3 .heading-collapse-indicator{margin-inline-start:-43px !important}.theme-dark.h1-align-left .markdown-preview-view h1 .heading-collapse-indicator,.theme-light.h1-align-left .markdown-preview-view h1 .heading-collapse-indicator{margin-inline-start:-50px !important}.markdown-source-view.mod-cm6 .cm-fold-indicator .collapse-indicator{inset-inline-end:22px}.h1-align-left .markdown-source-view.mod-cm6 .cm-fold-indicator .collapse-indicator{inset-inline-end:32px}.theme-light.h2-style-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .collapse-indicator,.theme-dark.h2-style-dark-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .collapse-indicator{inset-inline-end:-2px}.theme-light.h2-style-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .collapse-indicator svg,.theme-dark.h2-style-dark-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .collapse-indicator svg,.theme-light.h2-style-capsule .markdown-preview-view h2 .heading-collapse-indicator svg,.theme-dark.h2-style-dark-capsule .markdown-preview-view h2 .heading-collapse-indicator svg{color:#eee}.theme-light .markdown-preview-view h1,.theme-light .markdown-source-view.mod-cm6 .HyperMD-header-1{font-weight:700;line-height:1.4;padding-bottom:12px;display:table;width:auto;min-width:120px;text-align:center;margin-left:auto !important;margin-right:auto !important;position:relative;transition:color 0.3s ease, transform 0.3s ease}.theme-light .markdown-preview-view h1::after,.theme-light .markdown-source-view.mod-cm6 .HyperMD-header-1::after{content:'';position:absolute;bottom:0;left:50%;width:40px;height:4px;border-radius:4px;background:var(--h2-bg-gradient);background-size:100% auto;transform:translateX(-50%);transition:width 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s ease}.theme-light .markdown-preview-view h1:hover{color:var(--primary-color);transform:translateY(-2px)}.theme-light .markdown-preview-view h1:hover::after{width:100%}.theme-light.h1-align-left .markdown-preview-view h1,.theme-light.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1{text-align:left;margin-left:0 !important;margin-right:auto !important;padding-left:32px}.theme-light.h1-align-left .markdown-preview-view h1::before,.theme-light.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1::before{content:"";position:absolute;width:10px;height:22px;border-radius:6px;top:45%;transform:translateY(-50%);margin-top:-6px;left:2px;background-color:var(--secondary-color);opacity:0.5;transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);z-index:0}.theme-light.h1-align-left .markdown-preview-view h1::after,.theme-light.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1::after{bottom:auto;width:10px;height:22px;border-radius:6px;top:45%;transform:translateY(-50%);margin-top:4px;left:8px;background:var(--primary-color);mix-blend-mode:multiply;transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1) 0.05s;z-index:1}.theme-light.h1-align-left .markdown-preview-view h1:hover{transform:none;color:var(--primary-color)}.theme-light.h1-align-left .markdown-preview-view h1:hover::before{height:32px;margin-top:0;left:4px;width:6px;opacity:0.3;border-radius:3px}.theme-light.h1-align-left .markdown-preview-view h1:hover::after{height:26px;margin-top:0;left:12px;width:6px;border-radius:3px;box-shadow:0 0 10px color-mix(in srgb, var(--primary-color), transparent 60%)}.theme-light.h2-style-capsule .markdown-preview-view h2,.theme-light.h2-style-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2{color:#fff !important;font-weight:bold;text-decoration:none !important;display:inline-block;width:fit-content;padding:6px 16px;border-radius:8px;background-image:var(--h2-bg-gradient) !important;background-size:200% auto;background-position:0% center;background-repeat:no-repeat;box-shadow:0 2px 5px var(--h2-shadow-color);border:1px solid transparent !important;background-clip:padding-box;overflow:hidden;border-bottom:none !important;transition:background-position 0.5s ease-out, transform 0.4s ease, box-shadow 0.4s ease}.theme-light.h2-style-capsule .markdown-preview-view h2:hover{background-position:100% center;transform:scale(1.01);box-shadow:0 8px 20px var(--h2-shadow-hover)}.theme-light.h2-style-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2 .cm-formatting-header{color:rgba(255, 255, 255, 0.6) !important}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2,.theme-light.h2-style-twin .markdown-preview-view h2,.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2{background:none !important;box-shadow:none !important;border:none !important;border-radius:0 !important;position:relative;padding-left:20px;padding-right:0;display:block;width:100%;transition:color 0.3s ease}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2 .heading-collapse-indicator,.theme-light.h2-style-twin .markdown-preview-view h2 .heading-collapse-indicator{margin-inline-start:-43px !important}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2::before,.theme-light.h2-style-twin .markdown-preview-view h2::before,.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::before,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::before{content:"";position:absolute;left:0;top:auto;margin-top:0.1em;height:1em;width:5px;background-color:var(--primary-color);border-radius:4px;opacity:1;transition:all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1)}.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::before,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::before{margin-top:0.2em}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2::after,.theme-light.h2-style-twin .markdown-preview-view h2::after,.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::after,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::after{content:"";position:absolute;left:8px;top:auto;margin-top:0.3em;height:0.6em;width:2px;background-color:var(--secondary-color);border-radius:2px;opacity:0.6;transition:all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) 0.05s}.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::after,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::after{margin-top:0.4em}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2:hover,.theme-light.h2-style-twin .markdown-preview-view h2:hover{color:var(--primary-color) !important}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2:hover::before,.theme-light.h2-style-twin .markdown-preview-view h2:hover::before{top:auto;margin-top:0em;height:1.4em;opacity:0.4}.theme-light:not(.h2-style-capsule) .markdown-preview-view h2:hover::after,.theme-light.h2-style-twin .markdown-preview-view h2:hover::after{top:auto;margin-top:0.15em;height:1.1em;width:4px;opacity:1;background-color:var(--primary-color)}.theme-light:not(.h2-style-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2 .cm-formatting-header,.theme-light.h2-style-twin .markdown-source-view.mod-cm6 .HyperMD-header-2 .cm-formatting-header{color:var(--text-faint) !important;opacity:0.4}.theme-light .markdown-preview-view h3{width:fit-content;padding-left:15px;transition:all 0.3s cubic-bezier(.25, .8, .25, 1)}.theme-light .markdown-preview-view h3::before{content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);width:5px;height:1.3rem;border-radius:4px;background-color:var(--primary-color);transition:all .3s cubic-bezier(.25, .8, .25, 1)}.theme-light .markdown-preview-view h3:hover{padding-left:20px;color:var(--primary-color)}.theme-light .markdown-preview-view h3:hover::before{height:24px;width:7px}.theme-light .markdown-preview-view h4{padding-left:20px}.theme-light .markdown-preview-view h4::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);width:10px;height:10px;border-radius:50%;background-color:var(--primary-color);border:1px solid var(--primary-color);transition:all .3s ease}.theme-light .markdown-preview-view h4:hover{color:var(--light-deep);transform:translateX(6px)}.theme-light .markdown-preview-view h4:hover::before{transform:translateY(-50%) scale(1.3);box-shadow:0 0 0 4px var(--light-lighter)}.theme-light .markdown-preview-view h5{padding-left:20px}.theme-light .markdown-preview-view h5::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);width:10px;height:10px;border-radius:50%;background-color:#fff;border:2px solid var(--primary-color);box-sizing:border-box;transition:all .3s ease}.theme-light .markdown-preview-view h5:hover{color:var(--light-deep);transform:translateX(6px)}.theme-light .markdown-preview-view h5:hover::before{background-color:var(--primary-color);transform:translateY(-50%) scale(1.2);box-shadow:0 0 0 3px var(--light-lighter)}.theme-light .markdown-preview-view h6{padding-left:20px}.theme-light .markdown-preview-view h6::before{content:"-";position:absolute;left:0;top:50%;transform:translateY(-50%);color:var(--primary-color);font-weight:bold;line-height:1;transition:all .3s ease}.theme-light .markdown-preview-view h6:hover{color:var(--light-deep);transform:translateX(6px)}.theme-light .markdown-preview-view h6:hover::before{transform:translateY(-50%) scaleX(1.8)}.theme-dark .markdown-preview-view h1,.theme-dark .markdown-source-view.mod-cm6 .HyperMD-header-1{padding-bottom:12px;border-bottom:none;display:table;width:auto;min-width:120px;text-align:center;margin-top:2em;margin-bottom:1em;margin-left:auto !important;margin-right:auto !important;position:relative}.h1-align-left .markdown-preview-view h1{padding-bottom:0;}.theme-dark .markdown-preview-view h1::after,.theme-dark .markdown-source-view.mod-cm6 .HyperMD-header-1::after{content:'';position:absolute;bottom:0;left:50%;width:40px;height:4px;border-radius:4px;background:var(--h1-underline-color);box-shadow:0 0 5px rgba(255, 85, 85, 0.4);transform:translateX(-50%);transition:width 0.3s cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}.theme-dark .markdown-preview-view h1:hover{text-shadow:var(--glow-shadow-text)}.theme-dark .markdown-preview-view h1:hover::after{width:100%;box-shadow:0 0 15px var(--h1-underline-color)}.theme-dark.h1-align-left .markdown-preview-view h1,.theme-dark.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1{text-align:left;margin-left:0 !important;margin-right:auto !important;padding-left:32px}.theme-dark.h1-align-left .markdown-preview-view h1::before,.theme-dark.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1::before{content:"";position:absolute;top:45%;transform:translateY(-50%);margin-top:-6px;left:2px;width:10px;height:22px;border-radius:6px;background-color:var(--secondary-color);opacity:0.6;transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);z-index:0}.theme-dark.h1-align-left .markdown-preview-view h1::after,.theme-dark.h1-align-left .markdown-source-view.mod-cm6 .HyperMD-header-1::after{bottom:auto;top:45%;transform:translateY(-50%);margin-top:4px;left:8px;width:10px;height:22px;border-radius:6px;background:var(--primary-color);mix-blend-mode:screen;transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1) 0.05s;z-index:1}.theme-dark.h1-align-left .markdown-preview-view h1:hover{text-shadow:var(--glow-shadow-text)}.theme-dark.h1-align-left .markdown-preview-view h1:hover::before{height:32px;margin-top:0;left:4px;width:6px;opacity:0.4}.theme-dark.h1-align-left .markdown-preview-view h1:hover::after{height:26px;margin-top:0;left:12px;width:6px;box-shadow:0 0 15px var(--primary-color)}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2,.theme-dark.h2-style-dark-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2{width:fit-content;padding:5px 16px;border-radius:8px;display:inline-block;background-color:rgba(255, 255, 255, 0.02);background-image:var(--h2-bg-image);background-repeat:no-repeat;background-position:center bottom;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border-top:1px solid rgba(255, 255, 255, 0.08);border-left:1px solid transparent;border-right:1px solid transparent;border-bottom:1px solid transparent;position:relative;z-index:1;overflow:hidden;transition:color 0.5s ease, transform 0.5s ease, box-shadow 0.5s ease}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2::after,.theme-dark.h2-style-dark-capsule .markdown-source-view.mod-cm6 .HyperMD-header-2::after{content:"";position:absolute;inset:0;z-index:-1;background-image:var(--h2-bg-image-hover);background-repeat:no-repeat;background-position:center bottom;opacity:0;transition:opacity 0.5s ease}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2:hover{color:var(--primary-color);text-shadow:var(--glow-shadow-text);box-shadow:0 4px 12px rgba(0, 0, 0, 0.3);transform:translateY(-1px)}.theme-dark.h2-style-dark-capsule .markdown-preview-view h2:hover::after{opacity:1}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2,.theme-dark.h2-style-dark-twin .markdown-preview-view h2,.theme-dark:not(.h2-style-dark-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2,.theme-dark.h2-style-dark-twin .markdown-source-view.mod-cm6 .HyperMD-header-2{background:none !important;box-shadow:none !important;border:none !important;border-radius:0 !important;backdrop-filter:none !important;-webkit-backdrop-filter:none !important;position:relative;padding-left:20px;padding-right:0;display:block;width:100%;transition:color 0.3s ease}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2::before,.theme-dark.h2-style-dark-twin .markdown-preview-view h2::before,.theme-dark:not(.h2-style-dark-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::before,.theme-dark.h2-style-dark-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::before{content:"";position:absolute;left:0;top:auto;margin-top:0.2em;height:1em;width:5px;background-color:var(--primary-color);border-radius:4px;opacity:0.8;box-shadow:0 0 8px color-mix(in srgb, var(--primary-color), transparent 50%);transition:all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1)}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2::after,.theme-dark.h2-style-dark-twin .markdown-preview-view h2::after,.theme-dark:not(.h2-style-dark-capsule) .markdown-source-view.mod-cm6 .HyperMD-header-2::after,.theme-dark.h2-style-dark-twin .markdown-source-view.mod-cm6 .HyperMD-header-2::after{content:"";position:absolute;left:8px;top:auto;margin-top:0.4em;height:0.6em;width:2px;background-color:var(--secondary-color);border-radius:2px;opacity:0.6;transition:all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) 0.05s}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2:hover,.theme-dark.h2-style-dark-twin .markdown-preview-view h2:hover{color:var(--primary-color) !important;text-shadow:var(--glow-shadow-text)}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2:hover::before,.theme-dark.h2-style-dark-twin .markdown-preview-view h2:hover::before{top:auto;margin-top:0em;height:1.4em;opacity:0.5}.theme-dark:not(.h2-style-dark-capsule) .markdown-preview-view h2:hover::after,.theme-dark.h2-style-dark-twin .markdown-preview-view h2:hover::after{top:auto;margin-top:0.15em;height:1.1em;width:4px;opacity:1;background-color:var(--primary-color);box-shadow:0 0 12px var(--primary-color)}.theme-dark .markdown-preview-view h3{padding-left:15px;display:block;transition:padding-left 0.3s ease, color 0.3s ease}.theme-dark .markdown-preview-view h3::before{content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);width:4px;height:1.3rem;background:var(--primary-color);border-radius:2px;transition:all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);opacity:0.8}.theme-dark .markdown-preview-view h3:hover{color:var(--primary-color);padding-left:20px;text-shadow:var(--glow-shadow-text)}.theme-dark .markdown-preview-view h3:hover::before{height:24px;opacity:1;box-shadow:var(--glow-shadow-box)}.theme-dark .markdown-preview-view h4{display:flex;align-items:center}.theme-dark .markdown-preview-view h4::before{content:"";margin-right:10px;display:inline-block;background-color:var(--primary-color);width:8px;height:8px;border-radius:50%;transition:all 0.3s ease;flex-shrink:0}.theme-dark .markdown-preview-view h4:hover{color:var(--primary-color);text-shadow:var(--glow-shadow-text);transform:translateX(5px)}.theme-dark .markdown-preview-view h4:hover::before{transform:scale(1.2);box-shadow:var(--glow-shadow-box)}.theme-dark .markdown-preview-view h5{display:flex;align-items:center}.theme-dark .markdown-preview-view h5::before{content:"";margin-right:10px;display:inline-block;background-color:transparent;border:1.5px solid var(--primary-color);width:8px;height:8px;border-radius:50%;box-sizing:border-box;transition:all 0.3s ease;flex-shrink:0}.theme-dark .markdown-preview-view h5:hover{color:var(--primary-color);text-shadow:var(--glow-shadow-text);transform:translateX(5px)}.theme-dark .markdown-preview-view h5:hover::before{background-color:transparent;border-color:var(--primary-color);box-shadow:var(--glow-shadow-box);transform:scale(1.2)}.theme-dark .markdown-preview-view h6{display:flex;align-items:center}.theme-dark .markdown-preview-view h6::before{content:"-";color:var(--primary-color);margin-right:11px;display:inline-block;font-weight:bold;transition:all 0.3s ease}.theme-dark .markdown-preview-view h6:hover{color:var(--primary-color);text-shadow:var(--glow-shadow-text);transform:translateX(5px)}.theme-dark .markdown-preview-view h6:hover::before{text-shadow:var(--glow-shadow-text);transform:scaleX(1.5)}.markdown-preview-view h3::after,.markdown-preview-view h4::after,.markdown-preview-view h5::after,.markdown-preview-view h6::after{content:" ";display:inline-block;height:1.2em;width:1.2em;vertical-align:top;margin-left:8px;background-color:var(--primary-color);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;mask-repeat:no-repeat;mask-position:center;mask-size:contain;opacity:0.5}.theme-light h3::after,.theme-light h4::after,.theme-light h5::after,.theme-light h6::after{background-color:var(--light-light) !important;opacity:0.5}.markdown-preview-view h3::after{-webkit-mask-image:var(--h3-icon-shape);mask-image:var(--h3-icon-shape)}.markdown-preview-view h4::after{-webkit-mask-image:var(--h4-icon-shape);mask-image:var(--h4-icon-shape)}.markdown-preview-view h5::after{-webkit-mask-image:var(--h5-icon-shape);mask-image:var(--h5-icon-shape)}.markdown-preview-view h6::after{-webkit-mask-image:var(--h6-icon-shape);mask-image:var(--h6-icon-shape)}.markdown-source-view.mod-cm6 .HyperMD-header{font-weight:bold;line-height:1.4;position:relative}.markdown-source-view.mod-cm6 .cm-formatting-header{color:var(--primary-color);font-family:var(--font-monospace);font-weight:normal;margin-right:8px;opacity:0.4}.markdown-source-view.mod-cm6 .HyperMD-header-1{text-align:center;justify-content:center;border-bottom:none}.markdown-source-view.mod-cm6 .HyperMD-header-1::after{content:"";display:block;width:40px;height:4px;border-radius:4px;background:var(--primary-color);background-image:var(--h2-bg-gradient, linear-gradient(to right, var(--primary-color), var(--primary-color)));margin:8px auto 0 auto;opacity:0.8}.markdown-source-view.mod-cm6 .HyperMD-header-3{padding-left:20px}.markdown-source-view.mod-cm6 .HyperMD-header-3::before{content:"";position:absolute;margin-top:0.3rem;left:0;width:5px;height:1.3rem;border-radius:4px;background-color:var(--primary-color);opacity:0.8;pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header-4{padding-left:20px}.markdown-source-view.mod-cm6 .HyperMD-header-4::before{content:"";position:absolute;margin-top:0.46rem;left:0;width:10px;height:10px;border-radius:50%;background-color:var(--primary-color);border:1px solid var(--primary-color);pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header-5{padding-left:20px}.markdown-source-view.mod-cm6 .HyperMD-header-5::before{content:"";position:absolute;margin-top:0.5rem;left:0;width:10px;height:10px;border-radius:50%;background-color:transparent;border:2px solid var(--primary-color);box-sizing:border-box;background-color:var(--bg-color, transparent);pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header-6{padding-left:20px}.markdown-source-view.mod-cm6 .HyperMD-header-6::before{content:"-";position:absolute;left:0;color:var(--primary-color);font-weight:bold;line-height:1.4;font-family:var(--font-monospace);pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header:hover::before{opacity:1;border-color:var(--primary-color)}.markdown-source-view.mod-cm6 .HyperMD-header-3::after,.markdown-source-view.mod-cm6 .HyperMD-header-4::after,.markdown-source-view.mod-cm6 .HyperMD-header-5::after,.markdown-source-view.mod-cm6 .HyperMD-header-6::after{content:"";display:inline-block;vertical-align:top;width:1.2em;height:1.2em;margin-left:8px;background-color:var(--primary-color);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;mask-repeat:no-repeat;mask-position:center;mask-size:contain;opacity:0.3;pointer-events:none}.markdown-source-view.mod-cm6 .HyperMD-header-3::after{-webkit-mask-image:var(--h3-icon-shape);mask-image:var(--h3-icon-shape)}.markdown-source-view.mod-cm6 .HyperMD-header-4::after{-webkit-mask-image:var(--h4-icon-shape);mask-image:var(--h4-icon-shape)}.markdown-source-view.mod-cm6 .HyperMD-header-5::after{-webkit-mask-image:var(--h5-icon-shape);mask-image:var(--h5-icon-shape)}.markdown-source-view.mod-cm6 .HyperMD-header-6::after{-webkit-mask-image:var(--h6-icon-shape);mask-image:var(--h6-icon-shape)}.markdown-preview-view ul>li::marker,.markdown-preview-view ol>li::marker{color:var(--primary-color)}.markdown-preview-view em{padding:0 3px 0 0;color:var(--secondary-color)}.markdown-preview-view ul{list-style-type:disc}.markdown-preview-view ul ul{list-style-type:circle}.markdown-preview-view ul ul ul{list-style-type:square}.markdown-preview-view ol{list-style-type:decimal}.markdown-preview-view ol ol{list-style-type:lower-alpha}.markdown-preview-view ol ol ol{list-style-type:lower-roman}.markdown-preview-view ul>li>ol{padding-left:25px}.markdown-preview-view li{position:relative}.markdown-preview-view li::before{content:"";position:absolute;top:calc(var(--line-height-customize) * 1em);height:calc(100% - (var(--line-height-customize) * 1.5em));bottom:0;left:-18px;border-left:1px solid var(--primary-color);opacity:0.5;pointer-events:none}.markdown-preview-view ul>li::before{left:-0.83rem}.markdown-preview-view>div>ul>li::before,.markdown-preview-view>div>ol>li::before{display:none}.markdown-preview-view li.task-list-item::before{left:-0.7rem;height:calc(100% - var(--line-height-customize) * 1.4em)}.markdown-rendered.show-indentation-guide li>ul::before,.markdown-rendered.show-indentation-guide li>ol::before{display:none !important;border:none !important}.el-ol ol li{margin-left:35px}.markdown-source-view.mod-cm6 .HyperMD-list-line{--list-color:var(--text-muted)}.markdown-source-view.mod-cm6 .HyperMD-list-line-1,.markdown-source-view.mod-cm6 .HyperMD-list-line-2,.markdown-source-view.mod-cm6 .HyperMD-list-line-3,.markdown-source-view.mod-cm6 .HyperMD-list-line-4,.markdown-source-view.mod-cm6 .HyperMD-list-line-5,.markdown-source-view.mod-cm6 .HyperMD-list-line-6{--list-color:var(--primary-color)}.markdown-source-view.mod-cm6 .list-bullet{color:transparent !important;position:relative;margin-right:12px !important;display:inline-block}.markdown-source-view.mod-cm6 .list-bullet:after{content:"";position:absolute;top:50%;left:50%;transform:translate(-50%, -50%) scale(1.1);height:6px;width:6px;border-radius:50%;background-color:var(--list-color) !important;transition:all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)}.markdown-source-view.mod-cm6 .HyperMD-list-line:hover .list-bullet:after{transform:translate(-50%, -50%) scale(1.6);box-shadow:0 0 8px var(--list-color)}.markdown-source-view.is-live-preview{--list-padding-inline-start:0}.markdown-source-view.mod-cm6 .cm-indent::before{margin-inline-start:3px !important}.markdown-source-view.mod-cm6 .cm-active-indent::before{opacity:1 !important;box-shadow:0 0 8px var(--primary-color);z-index:1}.markdown-source-view.mod-cm6 .HyperMD-list-line .task-list-item-checkbox{border-color:var(--list-color) !important}.markdown-source-view.mod-cm6 .HyperMD-list-line .task-list-item-checkbox:checked{background-color:var(--list-color) !important;box-shadow:0 0 5px var(--list-color)}.markdown-source-view.mod-cm6 .list-number{color:var(--primary-color) !important;font-family:"Cascadia Code", "Lucida Console", monospace !important;font-weight:bold;margin-right:4px}.image-embed[alt*="right" i],.image-embed[alt*="+R" i],.image-embed[alt*="left" i],.image-embed[alt*="+L" i],.image-embed[alt*="center" i],.image-embed[alt*="+C" i],.image-embed[alt*="banner" i]{display:flex !important;width:100% !important;margin-top:0.5rem;margin-bottom:0.5rem}.image-embed[alt*="right" i],.image-embed[alt*="+R" i]{justify-content:flex-end}.image-embed[alt*="left" i],.image-embed[alt*="+L" i]{justify-content:flex-start}.image-embed[alt*="center" i],.image-embed[alt*="+C" i]{justify-content:center}.image-embed[alt*="right" i] img,.image-embed[alt*="+R" i] img,.image-embed[alt*="left" i] img,.image-embed[alt*="+L" i] img,.image-embed[alt*="center" i] img,.image-embed[alt*="+C" i] img{border-radius:8px;box-shadow:0 4px 15px rgba(0,0,0,0.05)}.image-embed[alt*="banner" i]{justify-content:center}.image-embed[alt*="banner" i] img{width:100% !important;max-height:250px;object-fit:cover;border-radius:12px;box-shadow:0 4px 15px rgba(0,0,0,0.05)}.markdown-preview-view ul.contains-task-list{margin-left:10px}.markdown-preview-view ul.contains-task-list{margin-left:10px}.markdown-preview-view input[type="checkbox"],.markdown-preview-view .task-list-item-checkbox{-webkit-appearance:none !important;appearance:none !important;background:transparent !important;border:none !important;border-radius:0 !important;outline:none !important;box-shadow:none !important;position:absolute !important;margin:0 !important;padding:0 !important;left:-1.3rem !important;top:calc((var(--line-height-customize) * 1.1rem - var(--checkbox-size)) / 2) !important;width:var(--checkbox-size) !important;height:var(--checkbox-size) !important;z-index:10;-webkit-mask-image:none !important;mask-image:none !important}.markdown-preview-view input[type="checkbox"]::before,.markdown-preview-view .task-list-item-checkbox::before{content:"" !important;display:block !important;position:absolute !important;inset:0 !important;width:1.2rem !important;height:1.2rem !important;border-radius:50% !important;background-color:var(--checkbox-bg-unchecked) !important;border:2px solid var(--checkbox-border-unchecked) !important;box-sizing:border-box !important;transition:all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.4);z-index:1}.markdown-preview-view input[type="checkbox"]:checked::before,.markdown-preview-view .task-list-item-checkbox:checked::before{border:1px solid var(--primary-color) !important;background-color:var(--checkbox-bg-checked) !important;box-shadow:var(--checkbox-shadow-checked) !important;animation:task-pulse 0.4s forwards}.markdown-preview-view input[type="checkbox"]::after,.markdown-preview-view .task-list-item-checkbox::after{content:"" !important;display:block !important;position:absolute !important;z-index:2 !important;top:45% !important;left:50% !important;width:0.45rem !important;height:0.25rem !important;background-color:transparent !important;-webkit-mask-image:none !important;mask-image:none !important;border:2.5px solid var(--checkmark-color) !important;border-top:0 !important;border-right:0 !important;transform:translate(-50%, -50%) rotate(-45deg) scale(0);opacity:0;transition:all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.4)}.markdown-preview-view input[type="checkbox"]:checked::after,.markdown-preview-view .task-list-item-checkbox:checked::after{opacity:1 !important;transform:translate(-50%, -50%) rotate(-45deg) scale(1) !important;border-color:var(--checkmark-color) !important}.markdown-preview-view .task-list-item[data-task="/"]{color:var(--text-normal) !important;text-decoration:none !important;opacity:1 !important}.markdown-preview-view .task-list-item[data-task="/"] p,.markdown-preview-view .task-list-item[data-task="/"] strong,.markdown-preview-view .task-list-item[data-task="/"] em,.markdown-preview-view .task-list-item[data-task="/"] code{text-decoration:none !important;color:inherit !important}.markdown-preview-view .task-list-item[data-task="/"] input[type="checkbox"]:checked::after{content:"" !important;border:none !important;width:6px !important;height:6px !important;border-radius:50% !important;background-color:var(--checkmark-color) !important;top:50% !important;left:50% !important;transform:translate(-50%, -50%) !important}.markdown-preview-view .task-list-item[data-task="-"]{color:var(--text-muted) !important;text-decoration:line-through !important;opacity:0.7 !important}.markdown-preview-view .task-list-item[data-task="-"] strong,.markdown-preview-view .task-list-item[data-task="-"] em{text-decoration:line-through !important;color:inherit !important}.markdown-preview-view .task-list-item[data-task="-"] input[type="checkbox"]:checked::before{background-color:var(--text-muted) !important;border-color:var(--text-muted) !important;box-shadow:none !important}.markdown-preview-view .task-list-item[data-task="-"] input[type="checkbox"]:checked::after{content:"\2715" !important;border:none !important;transform:none !important;background:transparent !important;font-size:13px !important;font-weight:800 !important;color:#ffffff !important;display:flex !important;align-items:center;justify-content:center;width:100% !important;height:100% !important;top:-1px !important;left:-0.3px !important}@keyframes task-pulse{0%{transform:scale(1)}50%{transform:scale(1.15)}100%{transform:scale(1)}}.markdown-preview-view .task-list-item{position:relative;list-style:none;padding-left:4px;min-height:calc(var(--line-height-customize) * 1em);transition:color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), opacity 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), text-decoration-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) !important;text-decoration:none !important;text-decoration-color:transparent !important;text-decoration-thickness:2px !important}.markdown-preview-view .task-list-item.is-checked{color:#888 !important;opacity:0.8;text-decoration-line:line-through !important;text-decoration-color:var(--text-color-secondary) !important}.markdown-preview-view .task-list-item.is-checked p,.markdown-preview-view .task-list-item.is-checked strong,.markdown-preview-view .task-list-item.is-checked em,.markdown-preview-view .task-list-item.is-checked mark,.markdown-preview-view .task-list-item.is-checked code{text-decoration:line-through !important;text-decoration-color:var(--text-color-secondary) !important;text-decoration-thickness:2px !important;color:inherit !important;opacity:1 !important}.markdown-preview-view blockquote p,.HyperMD-quote.HyperMD-quote-1.cm-line{line-height:var(--blockquote-line-height)}.theme-dark .markdown-preview-view blockquote{position:relative;margin:20px 0;padding:18px 20px 18px 48px;color:var(--text-color-secondary);background-color:rgba(0, 0, 0, 0.2);border:1px solid color-mix(in srgb, var(--secondary-color), transparent 70%);border-radius:16px;transition:all 0.3s ease}.theme-dark .markdown-preview-view blockquote::before{content:"💡";position:absolute;left:14px;top:18px;font-size:20px;line-height:1;filter:grayscale(1);opacity:0.8;transform:rotate(30deg);transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)}.theme-dark .markdown-preview-view blockquote p{color:var(--text-color-secondary);margin-block-start:0;margin-block-end:0;margin-bottom:0.5em}.theme-dark .markdown-preview-view blockquote p:last-child{margin-bottom:0}.theme-dark .markdown-preview-view blockquote:hover{border-color:var(--primary-color);background-color:color-mix(in srgb, var(--hover-background-color), transparent 95%);box-shadow:0 0 15px color-mix(in srgb, var(--hover-background-color), transparent 90%), inset 0 0 10px color-mix(in srgb, var(--hover-background-color), transparent 95%);transform:scale(1.01)}.theme-dark .markdown-preview-view blockquote:hover::before{filter:grayscale(0);opacity:1;transform:rotate(0deg);text-shadow:0 0 10px var(--primary-color)}.theme-light .markdown-preview-view blockquote{position:relative;margin:20px 0;padding:18px 20px 18px 48px;background-color:var(--blockquote-background-color);border:1px solid color-mix(in srgb, var(--primary-color), transparent 80%);border-radius:16px;color:var(--text-muted);transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), background-color 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease}.theme-light .markdown-preview-view blockquote::before{content:"✨";position:absolute;left:14px;top:18px;font-size:20px;line-height:1;font-family:"Segoe UI Emoji", "Apple Color Emoji", sans-serif;filter:none;opacity:1;transform:rotate(30deg);transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)}.theme-light .markdown-preview-view blockquote p{color:var(--text-muted);margin-block-start:0;margin-block-end:0;margin-bottom:0.5em}.theme-light .markdown-preview-view blockquote p:last-child{margin-bottom:0}.theme-light .markdown-preview-view blockquote:hover{transform:scale(1.02);background-color:color-mix(in srgb, var(--primary-color), white 92%);border-color:var(--primary-color);box-shadow:0 8px 20px color-mix(in srgb, var(--primary-color), transparent 85%)}.theme-light .markdown-preview-view blockquote:hover::before{transform:rotate(0deg);text-shadow:0 0 8px var(--primary-color)}.markdown-preview-view a.internal-link,.markdown-preview-view a.external-link,.markdown-source-view.mod-cm6 .cm-link .cm-underline,.markdown-source-view.mod-cm6 .cm-table-widget a{color:var(--secondary-color) !important;text-decoration:none !important;font-weight:500;padding:0 2px;margin:0;border-radius:4px;position:relative;border-bottom:none !important;background-image:none !important;padding-right:2px !important;cursor:pointer;transition:all 0.3s ease}.markdown-preview-view a.internal-link::before,.markdown-preview-view a.external-link::before,.markdown-source-view.mod-cm6 .cm-link .cm-underline::before,.markdown-source-view.mod-cm6 .cm-table-widget a::before{content:"[";display:inline-block;color:var(--text-muted);margin-right:1px;opacity:0.7;transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.3s, opacity 0.3s}.markdown-preview-view a.internal-link::after,.markdown-preview-view a.external-link::after,.markdown-source-view.mod-cm6 .cm-link .cm-underline::after,.markdown-source-view.mod-cm6 .cm-table-widget a::after{content:"]";display:inline-block;color:var(--text-muted);margin-left:1px;opacity:0.7;transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.3s, opacity 0.3s}.markdown-preview-view a.internal-link:hover,.markdown-preview-view a.external-link:hover,.markdown-source-view.mod-cm6 .cm-link .cm-underline:hover,.markdown-source-view.mod-cm6 .cm-table-widget a:hover{background-color:color-mix(in srgb, var(--primary-color), transparent 90%);color:var(--primary-color) !important;text-decoration:none !important}.markdown-preview-view a.internal-link:hover::before,.markdown-preview-view a.external-link:hover::before,.markdown-source-view.mod-cm6 .cm-link .cm-underline:hover::before,.markdown-source-view.mod-cm6 .cm-table-widget a:hover::before{transform:translateX(-4px);color:var(--primary-color);font-weight:bold;opacity:1}.markdown-preview-view a.internal-link:hover::after,.markdown-preview-view a.external-link:hover::after,.markdown-source-view.mod-cm6 .cm-link .cm-underline:hover::after,.markdown-source-view.mod-cm6 .cm-table-widget a:hover::after{transform:translateX(4px);color:var(--primary-color);font-weight:bold;opacity:1}.markdown-preview-view .external-link-icon,.markdown-source-view.mod-cm6 .cm-link .external-link,.markdown-source-view.mod-cm6 .cm-formatting-link-string.external-link,.markdown-source-view.mod-cm6 .cm-url.external-link{display:none !important;width:0 !important;height:0 !important;content:none !important;background-image:none !important;padding:0 !important;margin:0 !important}.markdown-preview-view table td a,.markdown-source-view.mod-cm6 .cm-table-widget a{padding:0 2px !important}.markdown-preview-view mark,.markdown-source-view.mod-cm6 mark,.markdown-source-view.mod-cm6 .cm-highlight{padding:0 2px;margin:0;border-radius:4px;font-weight:inherit;color:inherit;-webkit-box-decoration-break:clone;box-decoration-break:clone}.markdown-preview-view mark::before,.markdown-preview-view mark::after,.markdown-source-view.mod-cm6 mark::before,.markdown-source-view.mod-cm6 mark::after,.markdown-source-view.mod-cm6 .cm-highlight::before,.markdown-source-view.mod-cm6 .cm-highlight::after{content:none !important;display:none !important}.markdown-preview-view mark:not([style*="background"]),.markdown-source-view.mod-cm6 mark:not([style*="background"]),.markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]){background-color:transparent !important;background-repeat:no-repeat;background-position:0 100%;transition:background-size 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.3s ease, text-shadow 0.3s ease, box-shadow 0.3s ease}body.theme-light .markdown-preview-view mark:not([style*="background"]),body.theme-light .markdown-source-view.mod-cm6 mark:not([style*="background"]),body.theme-light .markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]){background-image:linear-gradient(to top, color-mix(in srgb, var(--primary-color), transparent 60%), transparent);background-size:100% 40%;color:var(--text-normal)}body.theme-light .markdown-preview-view mark:not([style*="background"]):hover,body.theme-light .markdown-source-view.mod-cm6 mark:not([style*="background"]):hover,body.theme-light .markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]):hover{background-size:100% 100%;background-image:linear-gradient(to top, color-mix(in srgb, var(--primary-color), transparent 40%), color-mix(in srgb, var(--primary-color), transparent 80%))}body.theme-dark .markdown-preview-view mark:not([style*="background"]),body.theme-dark .markdown-source-view.mod-cm6 mark:not([style*="background"]),body.theme-dark .markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]){background-image:linear-gradient(to top, color-mix(in srgb, var(--primary-color), transparent 50%), transparent) !important;background-size:100% 40%;color:color-mix(in srgb, var(--primary-color), white 20%) !important;text-shadow:none;box-shadow:none}body.theme-dark .markdown-preview-view mark:not([style*="background"]):hover,body.theme-dark .markdown-source-view.mod-cm6 mark:not([style*="background"]):hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-highlight:not([style*="background"]):hover{background-size:100% 100%;background-image:linear-gradient(to top, color-mix(in srgb, var(--primary-color), transparent 20%), color-mix(in srgb, var(--primary-color), transparent 80%)) !important;color:#fff !important;text-shadow:0 0 10px var(--primary-color);box-shadow:0 0 15px color-mix(in srgb, var(--primary-color), transparent 80%);transform:none}.markdown-preview-view strong,.markdown-source-view.mod-cm6 .cm-strong,.markdown-source-view.mod-cm6 strong{font-weight:bold;display:inline;position:relative;border-bottom:2px solid transparent;-webkit-box-decoration-break:clone;box-decoration-break:clone;transition:border-color 0.3s ease, color 0.3s ease, text-shadow 0.3s ease}body.theme-dark .markdown-preview-view strong,body.theme-dark .markdown-source-view.mod-cm6 .cm-strong,body.theme-dark .markdown-source-view.mod-cm6 strong{color:var(--primary-color)}body.theme-dark .markdown-preview-view strong:hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-strong:hover,body.theme-dark .markdown-source-view.mod-cm6 strong:hover{border-bottom-color:var(--primary-color);text-shadow:0 0 10px var(--primary-color);z-index:1}body.theme-light .markdown-preview-view strong,body.theme-light .markdown-source-view.mod-cm6 .cm-strong,body.theme-light .markdown-source-view.mod-cm6 strong{color:var(--text-bold)}body.theme-light .markdown-preview-view strong:hover,body.theme-light .markdown-source-view.mod-cm6 .cm-strong:hover,body.theme-light .markdown-source-view.mod-cm6 strong:hover{color:var(--primary-color) !important;border-bottom-color:color-mix(in srgb, var(--primary-color), transparent 70%);text-shadow:0 2px 10px color-mix(in srgb, var(--primary-color), transparent 60%)}.markdown-preview-view em,.markdown-source-view.mod-cm6 .cm-em,.markdown-source-view.mod-cm6 em{font-style:italic;text-decoration:none !important;padding-bottom:1px;background-repeat:repeat-x;background-position:0 100%;background-size:6px 3px;transition:color 0.2s ease, -webkit-text-stroke 0.2s ease, background-image 0.2s ease;-webkit-box-decoration-break:clone;box-decoration-break:clone}.markdown-preview-view em::after,.markdown-source-view.mod-cm6 .cm-em::after,.markdown-source-view.mod-cm6 em::after{content:none !important;display:none !important}@keyframes stitchFlow{from{background-position-x:0}to{background-position-x:6px}}body.theme-light .markdown-preview-view em,body.theme-light .markdown-source-view.mod-cm6 .cm-em,body.theme-light .markdown-source-view.mod-cm6 em{color:var(--secondary-color);background-image:linear-gradient(-45deg, transparent 35%, color-mix(in srgb, var(--secondary-color), transparent 60%) 35%, color-mix(in srgb, var(--secondary-color), transparent 60%) 65%, transparent 65%)}body.theme-light .markdown-preview-view em:hover,body.theme-light .markdown-source-view.mod-cm6 .cm-em:hover,body.theme-light .markdown-source-view.mod-cm6 em:hover{color:var(--primary-color);background-image:linear-gradient(-45deg, transparent 35%, var(--primary-color) 35%, var(--primary-color) 65%, transparent 65%);font-weight:normal;-webkit-text-stroke:0.6px var(--primary-color);animation:stitchFlow 0.5s linear infinite}body.theme-dark .markdown-preview-view em,body.theme-dark .markdown-source-view.mod-cm6 .cm-em,body.theme-dark .markdown-source-view.mod-cm6 em{color:var(--secondary-color);background-image:linear-gradient(-45deg, transparent 35%, color-mix(in srgb, var(--secondary-color), white 20%) 35%, color-mix(in srgb, var(--secondary-color), white 20%) 65%, transparent 65%)}body.theme-dark .markdown-preview-view em:hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-em:hover,body.theme-dark .markdown-source-view.mod-cm6 em:hover{color:var(--primary-color);background-image:linear-gradient(-45deg, transparent 35%, var(--primary-color) 35%, var(--primary-color) 65%, transparent 65%);font-weight:normal;-webkit-text-stroke:0.5px var(--primary-color);text-shadow:var(--glow-shadow-text);animation:stitchFlow 0.5s linear infinite}.markdown-preview-view s,.markdown-preview-view del,.markdown-source-view.mod-cm6 .cm-strikethrough{text-decoration:line-through;transition:all 0.3s ease}body.theme-dark .markdown-preview-view s,body.theme-dark .markdown-preview-view del,body.theme-dark .markdown-source-view.mod-cm6 .cm-strikethrough{text-decoration-color:var(--primary-color);color:#888}body.theme-dark .markdown-preview-view s:hover,body.theme-dark .markdown-preview-view del:hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-strikethrough:hover{opacity:1;color:var(--primary-color) !important;text-decoration-color:var(--secondary-color);cursor:not-allowed;text-shadow:0 0 8px var(--primary-color)}body.theme-light .markdown-preview-view s,body.theme-light .markdown-preview-view del,body.theme-light .markdown-source-view.mod-cm6 .cm-strikethrough{text-decoration-color:color-mix(in srgb, var(--primary-color), transparent 40%);color:#999}body.theme-light .markdown-preview-view s:hover,body.theme-light .markdown-preview-view del:hover,body.theme-light .markdown-source-view.mod-cm6 .cm-strikethrough:hover{opacity:1;color:var(--text-normal) !important;text-decoration-color:#ff5555;cursor:not-allowed;text-shadow:none}.markdown-preview-view hr{border:none;height:1px;background:linear-gradient(90deg, transparent, var(--primary-color), transparent);position:relative;overflow:visible;opacity:0.5;transition:all 0.3s ease}.markdown-preview-view hr::after{content:'';position:absolute;left:50%;top:50%;transform:translate(-50%, -50%) rotate(45deg);width:8px;height:8px;border:2px solid var(--primary-color);background-color:var(--bg-color);box-sizing:border-box;transition:all 0.3s ease}.markdown-preview-view hr:hover{opacity:1;background:linear-gradient(90deg, transparent, var(--primary-color), transparent)}.markdown-preview-view hr:hover::after{border-color:var(--primary-color);background-color:var(--primary-color);box-shadow:0 0 10px var(--primary-color);transform:translate(-50%, -50%) rotate(225deg) scale(1.5)}.markdown-preview-view table{border-collapse:separate !important;border-spacing:0 !important;width:100%;border:1px solid var(--border-color);border-radius:var(--table-border-radius);overflow:hidden;background-color:var(--table-bg);line-height:var(--table-line-height)}.markdown-preview-view table th,.markdown-preview-view table td{padding:10px 15px;color:var(--text-color);border-top:none !important;border-left:none !important;border-right:1px solid var(--table-border-inner);border-bottom:1px solid var(--table-border-inner);transition:all 0.2s ease}.markdown-preview-view table th:last-child,.markdown-preview-view table td:last-child{border-right:none !important}.markdown-preview-view table tr:last-child td{border-bottom:none !important}.markdown-preview-view table th{background-color:var(--table-th-bg) !important;color:var(--primary-color);font-weight:bold;white-space:nowrap;border-right:1px solid var(--table-th-border) !important;border-bottom:1px solid var(--table-th-border) !important}.markdown-preview-view table th:last-child{border-right:none !important}.markdown-preview-view table tbody tr:hover td{background-color:var(--table-row-hover-bg)}.markdown-preview-view table tbody td:hover{background-color:var(--table-cell-hover-bg);color:var(--table-cell-hover-text);box-shadow:inset 0 0 0 1px var(--primary-color);cursor:default}.markdown-preview-view table tr:nth-child(2n),.markdown-preview-view table tr:nth-child(2n+1){background-color:transparent !important}.markdown-preview-view table thead tr,.markdown-preview-view table thead tr:nth-child(2n),.markdown-preview-view table thead tr:nth-child(2n+1){background-color:transparent !important}.markdown-preview-view table th{background-color:var(--table-th-bg) !important}.theme-dark .markdown-preview-view table tbody td:hover{text-shadow:0 0 8px var(--primary-color)}.theme-light .markdown-preview-view table tbody td:hover{text-shadow:none}.markdown-source-view.mod-cm6 .cm-table-widget .table-editor{background-color:var(--table-bg) !important;border:1px solid var(--border-color) !important;border-radius:var(--table-border-radius);border-collapse:separate !important;margin-top:1em;margin-bottom:1em;width:100%}.markdown-source-view.mod-cm6 .cm-table-widget thead th{background-color:var(--table-th-bg) !important;color:var(--primary-color) !important;font-weight:bold;border-bottom:1px solid var(--table-th-border) !important;border-right:1px solid var(--table-th-border) !important;border-top:none !important;border-left:none !important;position:relative}.markdown-source-view.mod-cm6 .cm-table-widget tbody td{border-right:1px solid var(--table-border-inner) !important;border-bottom:1px solid var(--table-border-inner) !important;border-top:none !important;border-left:none !important;color:var(--text-color);transition:background-color 0.2s ease}.markdown-source-view.mod-cm6 .cm-table-widget .table-cell-wrapper{padding:10px 15px !important;display:block;min-height:100%}.markdown-source-view.mod-cm6 .cm-table-widget th:last-child,.markdown-source-view.mod-cm6 .cm-table-widget td:last-child{border-right:none !important}.markdown-source-view.mod-cm6 .cm-table-widget tbody tr:last-child td{border-bottom:none !important}.markdown-source-view.mod-cm6 .cm-table-widget tbody tr:hover td{background-color:var(--table-row-hover-bg)}.markdown-source-view.mod-cm6 .cm-table-widget tbody td:hover{background-color:var(--table-cell-hover-bg) !important;box-shadow:inset 0 0 0 1px var(--primary-color) !important}.markdown-source-view.mod-cm6 .cm-table-widget .table-col-drag-handle,.markdown-source-view.mod-cm6 .cm-table-widget .table-row-drag-handle{opacity:0;transition:opacity 0.2s ease;background-color:color-mix(in srgb, var(--border-color), transparent 70%)}.markdown-source-view.mod-cm6 .cm-table-widget th:hover .table-col-drag-handle,.markdown-source-view.mod-cm6 .cm-table-widget th:hover .table-row-drag-handle,.markdown-source-view.mod-cm6 .cm-table-widget td:hover .table-row-drag-handle{opacity:1}.markdown-source-view.mod-cm6 .cm-table-widget .table-row-btn,.markdown-source-view.mod-cm6 .cm-table-widget .table-col-btn{color:var(--text-muted);transition:all 0.2s ease;background-color:transparent}.markdown-source-view.mod-cm6 .cm-table-widget .table-row-btn{width:97%}.markdown-source-view.mod-cm6 .cm-table-widget .table-row-btn:hover,.markdown-source-view.mod-cm6 .cm-table-widget .table-col-btn:hover{border:none;color:var(--primary-color);background-color:transparent;transform:scale(1.1)}.markdown-source-view.mod-cm6 .cm-table-widget .cm-active{background-color:transparent !important}.markdown-rendered button.copy-code-button{top:-4px}.markdown-preview-view pre{position:relative;background-color:var(--code-background) !important;border:1px solid color-mix(in srgb, var(--border-color), transparent 50%) !important;border-radius:var(--code-radius);padding-top:38px !important;padding-bottom:12px;padding-left:0;padding-right:0;margin:20px 0;overflow:hidden;transition:border-color 0.3s ease, box-shadow 0.3s ease}.markdown-preview-view pre:hover{border-color:var(--primary-color) !important;box-shadow:0 4px 12px color-mix(in srgb, var(--primary-color), transparent 85%)}.markdown-preview-view pre::before{content:"";position:absolute;top:0;left:0;width:100%;height:32px;background-color:color-mix(in srgb, var(--primary-color), transparent 96%);background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDUwcHgiIGhlaWdodD0iMTMwcHgiPgogIDxlbGxpcHNlIGN4PSI2NSIgY3k9IjY1IiByeD0iNTAiIHJ5PSI1MiIgc3Ryb2tlPSJyZ2IoMjIwLDYwLDU0KSIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJyZ2IoMjM3LDEwOCw5NikiLz4KICA8ZWxsaXBzZSBjeD0iMjI1IiBjeT0iNjUiIHJ4PSI1MCIgcnk9IjUyIiAgc3Ryb2tlPSJyZ2IoMjE4LDE1MSwzMykiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0icmdiKDI0NywxOTMsODEpIi8+CiAgPGVsbGlwc2UgY3g9IjM4NSIgY3k9IjY1IiByeD0iNTAiIHJ5PSI1MiIgIHN0cm9rZT0icmdiKDI3LDE2MSwzNykiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0icmdiKDEwMCwyMDAsODYpIi8+Cjwvc3ZnPg==);background-repeat:no-repeat;background-size:54px;background-position:12px center;border-bottom:1px solid color-mix(in srgb, var(--border-color), transparent 70%);border-radius:8px 8px 0 0;z-index:5}.markdown-preview-view pre:hover::before{background-color:color-mix(in srgb, var(--primary-color), transparent 95%);border-bottom-color:color-mix(in srgb, var(--primary-color), transparent 80%)}.markdown-preview-view pre code{display:block;padding:0 16px;overflow-x:auto;color:var(--code-normal) !important;font-family:var(--font-monospace);line-height:var(--code-line-height);background-color:transparent !important}.markdown-preview-view pre.language-mermaid{padding-top:0 !important;background:transparent !important;border:none !important;box-shadow:none !important}.markdown-preview-view pre.language-mermaid::before{display:none !important}.markdown-preview-view .copy-code-button{background-color:transparent;color:var(--code-comment);top:4px;right:6px;height:24px;padding:0 8px;border-radius:4px;z-index:10;transition:all 0.2s}.markdown-preview-view .copy-code-button:hover{background-color:var(--primary-color);color:#fff}.markdown-preview-view pre:not([class]){padding-top:12px !important;padding-bottom:12px !important;padding-left:16px !important;padding-right:16px !important;background-color:color-mix(in srgb, var(--primary-color), transparent 96%) !important;border:none !important;border-left:4px solid var(--primary-color) !important;border-radius:4px !important;box-shadow:none !important;margin:16px 0}.markdown-preview-view pre:not([class])::before{content:none !important;display:none !important;height:0 !important;width:0 !important}.markdown-preview-view pre:not([class]) code{color:var(--text-normal) !important;font-family:var(--font-monospace);padding:0 !important;background-color:transparent !important;display:block;white-space:pre-wrap}body.theme-dark .markdown-preview-view pre:not([class]){background-color:rgba(255, 255, 255, 0.03) !important;border-left-color:var(--primary-color) !important}.markdown-source-view.mod-cm6 .HyperMD-codeblock{font-family:var(--font-monospace) !important;line-height:1.5;border-left:1px solid var(--code-border-color, rgba(189, 147, 249, 0.3));border-right:1px solid var(--code-border-color, rgba(189, 147, 249, 0.3))}.theme-dark .markdown-source-view.mod-cm6 .HyperMD-codeblock{background-color:rgba(255, 255, 255, 0.03) !important;color:var(--text-normal)}.theme-light .markdown-source-view.mod-cm6 .HyperMD-codeblock{background-color:var(--code-background) !important;--code-border-color:color-mix(in srgb, var(--primary-color), transparent 85%);border-left:1px solid var(--code-border-color);border-right:1px solid var(--code-border-color);color:var(--code-normal) !important}.markdown-source-view.mod-cm6 .HyperMD-codeblock-begin{border-top-left-radius:8px;border-top-right-radius:8px;padding-top:6px !important;padding-bottom:6px !important;margin-top:12px;position:relative;font-weight:bold;border-top:1px solid var(--code-border-color, rgba(189, 147, 249, 0.3))}.theme-dark .markdown-source-view.mod-cm6 .HyperMD-codeblock-begin{background-color:rgba(255, 255, 255, 0.08) !important;color:var(--secondary-color) !important}.theme-light .markdown-source-view.mod-cm6 .HyperMD-codeblock-begin{background-color:var(--code-block-header-bg, #f7f7f7) !important;color:var(--primary-color) !important}.markdown-source-view.mod-cm6 .HyperMD-codeblock-end{border-bottom-left-radius:8px;border-bottom-right-radius:8px;margin-bottom:12px;border-bottom:1px solid var(--code-border-color, rgba(189, 147, 249, 0.3))}.theme-dark .markdown-source-view.mod-cm6 .HyperMD-codeblock-end{color:var(--text-muted) !important}.theme-light .markdown-source-view.mod-cm6 .HyperMD-codeblock-end{color:var(--code-comment) !important}.theme-dark .markdown-source-view.mod-cm6 .HyperMD-codeblock.cm-active{background-color:rgba(255, 255, 255, 0.05) !important}.theme-light .markdown-source-view.mod-cm6 .HyperMD-codeblock.cm-active{background-color:color-mix(in srgb, var(--primary-color), transparent 94%) !important}.cm-keyword{color:var(--code-keyword) !important}.cm-def{color:var(--code-function) !important}.cm-string{color:var(--code-string) !important}.cm-number{color:var(--code-value) !important}.cm-comment{color:var(--code-comment) !important}.cm-variable{color:var(--code-operator) !important}.cm-property{color:var(--code-property) !important}.cm-type{color:var(--code-function) !important}.cm-atom{color:var(--code-value) !important}.theme-light .cm-punctuation,.theme-light .cm-operator{color:var(--code-punctuation, #555) !important}.callout{padding:12px 16px !important;margin-block:1em !important;border:none !important;border-radius:12px !important;position:relative !important;overflow:hidden !important;mix-blend-mode:normal;transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.3s ease, background-color 0.3s ease !important}.callout:hover{z-index:5}.callout-title{display:inline-flex !important;align-items:center;margin-bottom:12px !important;padding:4px 12px !important;border-radius:50px !important;font-weight:700;font-size:0.9em;line-height:1.2;color:inherit !important;background-color:rgba(255, 255, 255, 0.6) !important;border:1px solid rgba(0, 0, 0, 0.05) !important;position:relative;z-index:2}.callout-icon{display:inline-flex !important;align-items:center;justify-content:center;margin-right:6px !important;flex:0 0 auto !important;color:currentColor !important}.callout-icon svg{width:16px !important;height:16px !important;display:block !important;opacity:1 !important;fill:currentColor !important;stroke:currentColor !important;stroke-width:2px}.callout::after{content:"✨";position:absolute !important;right:-10px !important;bottom:-15px !important;font-family:"Segoe UI Emoji", "Apple Color Emoji", sans-serif;font-size:80px !important;line-height:1;opacity:0.12 !important;transform:rotate(-15deg);filter:grayscale(100%);pointer-events:none;z-index:0;transition:all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) !important}.callout:hover::after{transform:rotate(0deg) scale(1.1) !important;opacity:0.25 !important;right:0px !important;bottom:-5px !important;filter:grayscale(0%) !important}.callout-content{position:relative;z-index:2}.callout-content ul.contains-task-list{margin-left:2px}.markdown-source-view.mod-cm6 .callout-content ul.contains-task-list input.task-list-item-checkbox{transform:translateY(4px)}.theme-light .callout[data-callout="note"],.theme-light .callout[data-callout="info"],.theme-light .callout[data-callout="todo"]{background-color:rgba(48, 107, 214, 0.1) !important}.theme-light .callout[data-callout="note"] .callout-title{color:#6c5ce7 !important}.theme-light .callout[data-callout="note"]:hover{background-color:rgba(108, 92, 231, 0.15) !important}.theme-light .callout[data-callout="note"]::after{content:"📝";color:#6c5ce7}.theme-light .callout[data-callout="info"]::after{content:"ℹ️";color:#6c5ce7}.theme-light .callout[data-callout="todo"]::after{content:"✅";color:#6c5ce7}.theme-light .callout[data-callout="tip"]{background-color:rgba(0, 184, 148, 0.1) !important}.theme-light .callout[data-callout="tip"] .callout-title{color:#00b894 !important}.theme-light .callout[data-callout="tip"]:hover{background-color:rgba(0, 184, 148, 0.15) !important}.theme-light .callout[data-callout="tip"]::after{content:"💡";color:#00b894}.theme-light .callout[data-callout="warning"]{background-color:rgba(253, 203, 110, 0.15) !important}.theme-light .callout[data-callout="warning"] .callout-title{color:#e17055 !important}.theme-light .callout[data-callout="warning"]:hover{background-color:rgba(253, 203, 110, 0.2) !important}.theme-light .callout[data-callout="warning"]::after{content:"⚠️";color:#e17055}.theme-light .callout[data-callout="important"]{background-color:rgba(255, 118, 117, 0.12) !important}.theme-light .callout[data-callout="important"] .callout-title{color:#ff7675 !important}.theme-light .callout[data-callout="important"]:hover{background-color:rgba(255, 118, 117, 0.18) !important}.theme-light .callout[data-callout="important"]::after{content:"📌";color:#ff7675}.theme-light .callout[data-callout="caution"],.theme-light .callout[data-callout="bug"]{background-color:rgba(214, 48, 49, 0.08) !important}.theme-light .callout[data-callout="caution"] .callout-title{color:#d63031 !important}.theme-light .callout[data-callout="caution"]:hover{background-color:rgba(214, 48, 49, 0.12) !important}.theme-light .callout[data-callout="caution"]::after{content:"🔥";color:#d63031}.theme-light .callout[data-callout="success"],.theme-light .callout[data-callout="done"]{background-color:rgba(85, 239, 196, 0.15) !important}.theme-light .callout[data-callout="success"] .callout-title{color:#00b894 !important}.theme-light .callout[data-callout="success"]:hover{background-color:rgba(85, 239, 196, 0.25) !important}.theme-light .callout[data-callout="success"]::after{content:"🎉";color:#00b894}.theme-light .callout[data-callout="example"]{background-color:rgba(162, 155, 254, 0.15) !important}.theme-light .callout[data-callout="example"] .callout-title{color:#6c5ce7 !important}.theme-light .callout[data-callout="example"]:hover{background-color:rgba(162, 155, 254, 0.25) !important}.theme-light .callout[data-callout="example"]::after{content:"🧩";color:#6c5ce7}.theme-light .callout[data-callout="quote"]{background-color:rgba(178, 190, 195, 0.15) !important}.theme-light .callout[data-callout="quote"] .callout-title{color:#636e72 !important}.theme-light .callout[data-callout="quote"]:hover{background-color:rgba(178, 190, 195, 0.25) !important}.theme-light .callout[data-callout="quote"]::after{content:"💬";color:#636e72}.theme-light .callout[data-callout="danger"],.theme-light .callout[data-callout="error"]{background-color:rgba(214, 48, 49, 0.15) !important;border-left-color:#d63031 !important}.theme-light .callout[data-callout="danger"] .callout-title,.theme-light .callout[data-callout="error"] .callout-title{color:#d63031 !important}.theme-light .callout[data-callout="danger"]:hover,.theme-light .callout[data-callout="error"]:hover{background-color:rgba(214, 48, 49, 0.2) !important}.theme-light .callout[data-callout="danger"]::after{content:"⚡";color:#d63031}.theme-light .callout[data-callout="error"]::after{content:"❌";color:#d63031}.theme-light .callout[data-callout="bug"]::after{content:"🐛";color:#d63031}.theme-light .callout[data-callout="failure"],.theme-light .callout[data-callout="missing"]{background-color:rgba(45, 52, 54, 0.05) !important}.theme-light .callout[data-callout="failure"] .callout-title{color:#c0392b !important}.theme-light .callout[data-callout="failure"]:hover{background-color:rgba(45, 52, 54, 0.1) !important}.theme-light .callout[data-callout="failure"]::after{content:"📉";color:#c0392b}.theme-light .callout[data-callout="question"],.theme-light .callout[data-callout="faq"],.theme-light .callout[data-callout="help"]{background-color:rgba(253, 203, 110, 0.15) !important}.theme-light .callout[data-callout="question"] .callout-title{color:#f39c12 !important}.theme-light .callout[data-callout="question"]:hover{background-color:rgba(253, 203, 110, 0.25) !important}.theme-light .callout[data-callout="question"]::after{content:"❓";color:#f39c12}.theme-light .callout[data-callout="abstract"],.theme-light .callout[data-callout="summary"],.theme-light .callout[data-callout="tldr"]{background-color:rgba(129, 236, 236, 0.2) !important}.theme-light .callout[data-callout="abstract"] .callout-title{color:#00cec9 !important}.theme-light .callout[data-callout="abstract"]:hover{background-color:rgba(129, 236, 236, 0.3) !important}.theme-light .callout[data-callout="abstract"]::after{content:"📑";color:#00cec9}.theme-dark .callout{background-color:rgba(255, 255, 255, 0.03) !important;border:1px solid rgba(255, 255, 255, 0.05) !important}.theme-dark .callout-title{background-color:rgba(255, 255, 255, 0.08) !important;border:1px solid rgba(255, 255, 255, 0.1) !important;color:var(--text-normal) !important}.theme-dark .callout[data-callout="note"]{border-color:rgba(189, 147, 249, 0.3) !important;background-color:rgba(189, 147, 249, 0.1) !important}.theme-dark .callout[data-callout="note"] .callout-title{color:#bd93f9 !important}.theme-dark .callout[data-callout="note"]:hover{background-color:rgba(189, 147, 249, 0.2) !important}.theme-dark .callout[data-callout="note"]::after{content:"📝";color:#bd93f9}.theme-dark .callout[data-callout="tip"]{border-color:rgba(139, 233, 253, 0.3) !important;background-color:rgba(139, 233, 253, 0.1) !important}.theme-dark .callout[data-callout="tip"] .callout-title{color:#8be9fd !important}.theme-dark .callout[data-callout="tip"]:hover{background-color:rgba(139, 233, 253, 0.2) !important}.theme-dark .callout[data-callout="tip"]::after{content:"💡";color:#8be9fd}.theme-dark .callout[data-callout="warning"]{border-color:rgba(255, 184, 108, 0.3) !important;background-color:rgba(255, 184, 108, 0.1) !important}.theme-dark .callout[data-callout="warning"] .callout-title{color:#ffb86c !important}.theme-dark .callout[data-callout="warning"]:hover{background-color:rgba(255, 184, 108, 0.2) !important}.theme-dark .callout[data-callout="warning"]::after{content:"⚠️";color:#ffb86c}.theme-dark .callout[data-callout="important"]{border-color:rgba(255, 85, 85, 0.3) !important;background-color:rgba(255, 85, 85, 0.1) !important}.theme-dark .callout[data-callout="important"] .callout-title{color:#ff5555 !important}.theme-dark .callout[data-callout="important"]:hover{background-color:rgba(255, 85, 85, 0.2) !important}.theme-dark .callout[data-callout="important"]::after{content:"🔥";color:#ff5555}.theme-dark .callout[data-callout="info"]{border-color:rgba(116, 192, 252, 0.3) !important;background-color:rgba(116, 192, 252, 0.1) !important}.theme-dark .callout[data-callout="info"] .callout-title{color:#74c0fc !important}.theme-dark .callout[data-callout="info"]::after{content:"ℹ️";color:#74c0fc}.theme-dark .callout[data-callout="todo"]{border-color:rgba(80, 250, 123, 0.3) !important;background-color:rgba(80, 250, 123, 0.1) !important}.theme-dark .callout[data-callout="todo"] .callout-title{color:#50fa7b !important}.theme-dark .callout[data-callout="todo"]::after{content:"✅";color:#50fa7b}.theme-dark .callout[data-callout="success"],.theme-dark .callout[data-callout="done"]{border-color:rgba(85, 239, 196, 0.3) !important;background-color:rgba(85, 239, 196, 0.1) !important}.theme-dark .callout[data-callout="success"] .callout-title{color:#55efc4 !important}.theme-dark .callout[data-callout="success"]:hover{background-color:rgba(85, 239, 196, 0.15) !important}.theme-dark .callout[data-callout="success"]::after{content:"🎉";color:#55efc4}.theme-dark .callout[data-callout="question"],.theme-dark .callout[data-callout="faq"],.theme-dark .callout[data-callout="help"]{border-color:rgba(241, 250, 140, 0.3) !important;background-color:rgba(241, 250, 140, 0.1) !important}.theme-dark .callout[data-callout="question"] .callout-title{color:#f1fa8c !important}.theme-dark .callout[data-callout="question"]:hover{background-color:rgba(241, 250, 140, 0.15) !important}.theme-dark .callout[data-callout="question"]::after{content:"❓";color:#f1fa8c}.theme-dark .callout[data-callout="example"]{border-color:rgba(255, 121, 198, 0.3) !important;background-color:rgba(255, 121, 198, 0.1) !important}.theme-dark .callout[data-callout="example"] .callout-title{color:#ff79c6 !important}.theme-dark .callout[data-callout="example"]:hover{background-color:rgba(255, 121, 198, 0.15) !important}.theme-dark .callout[data-callout="example"]::after{content:"🧩";color:#ff79c6}.theme-dark .callout[data-callout="quote"]{border-color:rgba(223, 230, 233, 0.2) !important;background-color:rgba(223, 230, 233, 0.05) !important}.theme-dark .callout[data-callout="quote"] .callout-title{color:#dfe6e9 !important}.theme-dark .callout[data-callout="quote"]::after{content:"💬";color:#dfe6e9}.theme-dark .callout[data-callout="danger"],.theme-dark .callout[data-callout="error"]{border-color:rgba(255, 85, 85, 0.4) !important;background-color:rgba(255, 85, 85, 0.1) !important;box-shadow:0 0 10px rgba(255, 85, 85, 0.1)}.theme-dark .callout[data-callout="danger"] .callout-title,.theme-dark .callout[data-callout="error"] .callout-title{color:#ff5555 !important}.theme-dark .callout[data-callout="danger"]::after{content:"⚡";color:#ff5555}.theme-dark .callout[data-callout="error"]::after{content:"❌";color:#ff5555}*/ .theme-dark .callout[data-callout="bug"]{border-color:rgba(255, 85, 85, 0.4) !important;background-color:rgba(255, 85, 85, 0.1) !important}.theme-dark .callout[data-callout="bug"] .callout-title{color:#ff5555 !important}.theme-dark .callout[data-callout="bug"]::after{content:"🐛";color:#ff5555}.theme-dark .callout[data-callout="failure"],.theme-dark .callout[data-callout="missing"]{border-color:rgba(179, 57, 57, 0.3) !important;background-color:rgba(0, 0, 0, 0.2) !important}.theme-dark .callout[data-callout="failure"] .callout-title{color:#fab1a0 !important}.theme-dark .callout[data-callout="failure"]::after{content:"📉";color:#fab1a0}.theme-dark .callout[data-callout="abstract"],.theme-dark .callout[data-callout="summary"]{border-color:rgba(129, 236, 236, 0.3) !important;background-color:rgba(129, 236, 236, 0.1) !important}.theme-dark .callout[data-callout="abstract"] .callout-title{color:#81ecec !important}.theme-dark .callout[data-callout="abstract"]::after{content:"📑";color:#81ecec}.markdown-source-view.mod-cm6 .cm-embed-block:not(.cm-table-widget, .cm-lang-base):hover{box-shadow:none}.markdown-preview-view :not(pre)>code,.markdown-source-view.mod-cm6 .cm-inline-code:not(.cm-formatting){font-family:var(--font-monospace) !important;letter-spacing:0.5px;background-color:color-mix(in srgb, var(--primary-color), transparent 90%);color:var(--primary-color) !important;border:1px solid color-mix(in srgb, var(--primary-color), transparent 85%);padding:2px 6px !important;margin:0 2px;border-radius:6px;vertical-align:middle;transition:all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);-webkit-box-decoration-break:clone;box-decoration-break:clone}.markdown-preview-view :not(pre)>code:hover{background-color:var(--primary-color) !important;color:#fff !important;border-color:var(--primary-color);box-shadow:0 0 15px color-mix(in srgb, var(--primary-color), transparent 60%);transform:scale(1.05);text-decoration:none !important;-webkit-text-fill-color:#fff !important;position:relative;z-index:1}.markdown-source-view.mod-cm6 .cm-formatting-code{color:var(--primary-color) !important;opacity:0.4;font-family:var(--font-monospace);font-weight:bold}.markdown-preview-view kbd,.markdown-source-view.mod-cm6 .cm-kbd,.markdown-source-view.mod-cm6 kbd{font-family:var(--font-monospace), "CascadiaCode", Consolas, monospace;font-size:0.9em;font-weight:600;line-height:1;text-align:center;display:inline-block;min-width:1.6em;padding:3px 6px;margin:0 4px;border-radius:6px;vertical-align:middle;transition:all 0.15s cubic-bezier(0.25, 0.8, 0.25, 1);text-shadow:none;cursor:default}body.theme-dark .markdown-preview-view kbd,body.theme-dark .markdown-source-view.mod-cm6 .cm-kbd,body.theme-dark .markdown-source-view.mod-cm6 kbd{background-color:#333;color:var(--text-color);border:1px solid #444;border-top-color:#555;border-bottom-color:#222;box-shadow:0 4px 0 #222, 0 5px 5px rgba(0, 0, 0, 0.4)}body.theme-dark .markdown-preview-view kbd:hover,body.theme-dark .markdown-source-view.mod-cm6 .cm-kbd:hover,body.theme-dark .markdown-source-view.mod-cm6 kbd:hover{transform:translateY(2px);box-shadow:0 2px 0 #222, 0 3px 3px rgba(0, 0, 0, 0.4);color:var(--primary-color);border-color:var(--primary-color)}body.theme-light .markdown-preview-view kbd,body.theme-light .markdown-source-view.mod-cm6 .cm-kbd,body.theme-light .markdown-source-view.mod-cm6 kbd{background-color:#fff;color:var(--primary-color);border:1px solid var(--primary-color);border-bottom-width:3px;box-shadow:0 2px 4px color-mix(in srgb, var(--primary-color), transparent 85%)}body.theme-light .markdown-preview-view kbd:hover,body.theme-light .markdown-source-view.mod-cm6 .cm-kbd:hover,body.theme-light .markdown-source-view.mod-cm6 kbd:hover{transform:translateY(2px);border-bottom-width:1px;background-color:color-mix(in srgb, var(--primary-color), transparent 90%);box-shadow:none}.mermaid{display:block !important;width:100% !important;overflow-x:auto !important;overflow-y:hidden;margin:1em 0;padding-bottom:8px;text-align:center;background-color:transparent !important}.mermaid .node rect,.mermaid .node circle,.mermaid .node ellipse,.mermaid .node path{fill:color-mix(in srgb, var(--primary-color), transparent 90%) !important;stroke:var(--primary-color) !important;stroke-width:1.5px !important;opacity:1 !important}.mermaid .node polygon{fill:color-mix(in srgb, var(--secondary-color), transparent 85%) !important;stroke:var(--secondary-color) !important;stroke-width:1.5px !important}.mermaid .label,.mermaid foreignObject,.mermaid foreignObject div,.mermaid foreignObject span,.mermaid foreignObject p,.mermaid span.nodeLabel{font-size:12px !important}.edgeLabel p{background-color:color-mix(in srgb, var(--primary-color), white 90%)!important;border:1px solid var(--primary-color) !important;border-radius:4px !important;letter-spacing:0!important;padding:0 3px}.cluster rect{fill:color-mix(in srgb, var(--secondary-color), transparent 90%)!important;stroke:var(--secondary-color)!important;stroke-width:1px!important;stroke-linejoin:round;rx:5px;ry:5px}.cluster-label span p{letter-spacing:0!important}#m54fff87155a51594 .actor{fill:color-mix(in srgb, var(--primary-color), white 90%)!important;stroke:var(--primary-color) !important;rx:5px;ry:5px}.statediagram-cluster rect{fill:color-mix(in srgb, var(--primary-color), white 90%)!important;stroke:var(--primary-color) !important}.mermaid *{letter-spacing:0}.mermaid foreignObject{overflow:visible !important}.mermaid .node .label,.mermaid .label{stroke:none !important}.mermaid::-webkit-scrollbar{height:6px}.mermaid::-webkit-scrollbar-track{background:rgba(255, 255, 255, 0.05);border-radius:3px}.mermaid::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:3px}.mermaid::-webkit-scrollbar-thumb:hover{background:var(--secondary-color)}.community-modal-info{--h2-color:var(--primary-color)}.nav-file-tag{line-height:1rem}.modal{background-color:var(--background-primary);border-radius:16px;border:1px solid var(--border-color);box-shadow:0 20px 60px -10px rgba(0, 0, 0, 0.4);overflow:auto;max-width:1100px;transition:transform 0.2s ease, opacity 0.2s ease}.theme-dark .modal{background-color:rgba(20, 20, 25, 0.85);backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);border:1px solid rgba(255, 255, 255, 0.08);box-shadow:0 0 0 1px rgba(0, 0, 0, 0.2), 0 30px 80px -10px rgba(0, 0, 0, 0.6)}.theme-light .modal{background-color:rgba(255, 255, 255, 0.85);backdrop-filter:blur(20px) saturate(120%);-webkit-backdrop-filter:blur(20px) saturate(120%);border:1px solid rgba(0, 0, 0, 0.05);box-shadow:0 10px 40px -5px rgba(0, 0, 0, 0.1)}.modal-close-button{position:absolute;top:16px;right:16px;z-index:10;opacity:0.6;transition:all 0.2s ease}.modal-close-button:hover{opacity:1;background-color:var(--background-modifier-hover);color:var(--text-error);transform:rotate(90deg)}.vertical-tab-header{background-color:color-mix(in srgb, var(--background-secondary), transparent 60%);border-right:1px solid var(--border-color);width:230px;padding:15px 8px;flex-shrink:0}.vertical-tab-header-group-title{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:var(--text-muted);margin:2px 0 4px 10px}.vertical-tab-nav-item{display:flex;align-items:center;padding:5px 10px;margin-bottom:2px;border-radius:6px;cursor:pointer;font-size:14px;color:var(--text-normal);transition:all 0.2s ease;position:relative}.vertical-tab-nav-item-icon{margin-right:8px;color:var(--text-muted);display:flex;align-items:center;transition:color 0.2s ease}.vertical-tab-nav-item-icon svg{width:16px;height:16px;stroke-width:2px}.vertical-tab-nav-item:hover{background-color:var(--background-modifier-hover);color:var(--text-normal)}.vertical-tab-nav-item:hover .vertical-tab-nav-item-icon{color:var(--text-normal)}.vertical-tab-nav-item.is-active{background-color:var(--primary-color) !important;color:#ffffff !important;font-weight:600;box-shadow:0 2px 8px color-mix(in srgb, var(--primary-color), transparent 50%)}.vertical-tab-nav-item.is-active .vertical-tab-nav-item-icon{color:#ffffff !important;opacity:1}.workspace-leaf-content[data-type="bases"]{--bases-table-row-border-width:0px !important;--bases-table-column-border-width:0px !important;--table-border-width:0px !important;--bases-table-row-height:40px !important;--bases-table-font-size:14px !important;--bases-table-header-background:var(--background-primary);--bases-table-group-background:var(--background-primary)}.bases-toolbar{border-bottom:1px solid var(--border-color);padding:8px 16px;gap:12px}.bases-toolbar .text-icon-button{background-color:transparent;border:1px solid transparent;border-radius:8px;padding:4px 12px;color:var(--text-muted);font-size:13px;transition:all 0.2s ease;box-shadow:none !important}.bases-toolbar .text-icon-button:hover,.bases-toolbar .text-icon-button.is-active{background-color:var(--background-modifier-hover);color:var(--text-normal)}.bases-toolbar .text-button-icon svg{width:16px;height:16px;opacity:0.8}.bases-thead{background-color:var(--background-primary) !important;border-bottom:2px solid var(--background-modifier-border);box-shadow:none !important;z-index:10}.bases-table-header{color:var(--text-muted);font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;padding-left:12px}.bases-tr{box-shadow:none !important;border-bottom:1px solid transparent;transition:all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);cursor:pointer;margin:0 4px;width:calc(100% - 8px) !important;border-radius:8px}.bases-tr:hover{background-color:color-mix(in srgb, var(--primary-color), transparent 88%) !important;box-shadow:0 2px 8px rgba(0, 0, 0, 0.05), inset 0 0 0 1px color-mix(in srgb, var(--primary-color), transparent 90%) !important;border-bottom-color:transparent;transform:scale(1.005);z-index:10}.bases-tr:hover .bases-rendered-value{color:var(--text-normal) !important}.bases-tr:hover .internal-link{color:var(--primary-color) !important;text-decoration:none !important}.bases-tr.is-selected{background-color:color-mix(in srgb, var(--primary-color), transparent 80%) !important;box-shadow:inset 3px 0 0 var(--primary-color)}.bases-tr:hover .bases-td:first-child{border-top-left-radius:8px;border-bottom-left-radius:8px}.bases-tr:hover .bases-td:last-child{border-top-right-radius:8px;border-bottom-right-radius:8px}.bases-td{box-shadow:none !important;padding:0 12px !important;border-right:none !important}.bases-rendered-value{padding:0 !important;display:flex;align-items:center}.bases-rendered-value .internal-link{text-decoration:none !important;color:var(--text-normal) !important;font-weight:400;transition:color 0.2s ease}.bases-rendered-value .internal-link:hover{color:var(--primary-color) !important;text-decoration:underline !important;text-underline-offset:4px}.bases-table-header-icon{display:none}.bases-view{background-color:var(--background-primary)}.theme-light .bases-tr:not(:hover){border-bottom:1px solid rgba(0, 0, 0, 0.03)}.theme-dark .bases-tr:not(:hover){border-bottom:1px solid rgba(255, 255, 255, 0.03)}body{--scrollbar-bg:transparent;--scrollbar-thumb-bg:rgba(var(--mono-rgb-100), 0.1);--scrollbar-active-thumb-bg:rgba(var(--mono-rgb-100), 0.2)}body.theme-dark{--scrollbar-thumb-bg:rgba(255, 255, 255, 0.1);--scrollbar-active-thumb-bg:rgba(255, 255, 255, 0.2)}body.theme-light{--scrollbar-thumb-bg:rgba(0, 0, 0, 0.1);--scrollbar-active-thumb-bg:rgba(0, 0, 0, 0.2)}body:not(.restored-scrollbars) ::-webkit-scrollbar,body:not(.restored-scrollbars) .kanban-plugin__scroll-container::-webkit-scrollbar{width:8px;height:8px;background-color:var(--scrollbar-bg)}body:not(.restored-scrollbars) ::-webkit-scrollbar-thumb,body:not(.restored-scrollbars) .kanban-plugin__scroll-container::-webkit-scrollbar-thumb{background-clip:padding-box;border-radius:20px;border:2px solid transparent;min-height:45px;background-color:transparent}body:not(.restored-scrollbars) .mobile-toolbar-options-container::-webkit-scrollbar{display:none}body:not(.restored-scrollbars):not(.is-mobile) :hover::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-bg) !important}body:not(.restored-scrollbars) ::-webkit-scrollbar-thumb:hover,body:not(.restored-scrollbars) ::-webkit-scrollbar-thumb:active{background-color:var(--scrollbar-active-thumb-bg) !important}.workspace-leaf-content:is([data-type="surfing-view"], [data-type="graph"], [data-type="localgraph"]) ::-webkit-scrollbar,.scrollbar-hide ::-webkit-scrollbar{display:none}body.layout-cards:not(.is-mobile) .workspace-tabs:not(.mod-stacked) .workspace-leaf,body.layout-cards:not(.is-mobile) .workspace-tabs:not(.mod-stacked) .workspace-leaf-content,body.layout-cards:not(.is-mobile) .workspace-tabs:not(.mod-stacked) .view-header:not(.animate),body.layout-cards:not(.is-mobile) .workspace-tabs:not(.mod-stacked) .view-content:not(.vignette-radial, .vignette-linear, .animate, .ptm-fullscreen-writing-focus-element),body.layout-cards .mod-left-split .workspace-tab-header.has-active-menu,body.layout-cards .mod-right-split .workspace-tab-header.has-active-menu,body.layout-cards:not(.is-mobile) .workspace-tab-header-container,body.layout-cards .workspace>.workspace-split{background-color:transparent !important}body.layout-cards .workspace-tab-header-container,body.layout-cards .workspace-tabs.mod-top .workspace-tab-header-container,body.layout-cards .workspace-ribbon.mod-left:before{border-bottom:1px solid var(--background-card) !important}body.layout-cards .workspace-ribbon{border-right:transparent !important;background-color:var(--background-card)}body.layout-cards .sidebar-toggle-button,body.layout-cards .workspace-tabs.mod-top{background-color:var(--background-card)}body.layout-cards .workspace-ribbon.mod-left:before{background:transparent !important}body.layout-cards .workspace-leaf-resize-handle{--workspace-divider-color:transparent;border-color:var(--workspace-divider-color)}body.layout-cards .is-hidden-frameless:not(.is-fullscreen).is-focused .titlebar-button-container.mod-right{background-color:transparent}body.layout-cards:not(.is-mobile).mod-left-split .workspace-sidedock-vault-profile{border:0;padding:0;z-index:99}body.layout-cards .workspace-sidedock-vault-profile{border-top:transparent !important}body.layout-cards:not(.is-mobile) .workspace-split.mod-left-split .workspace-sidedock-vault-profile{background-color:var(--background-card)}body.layout-cards:not(.is-mobile) .workspace-split.mod-left-split{position:relative}body.layout-cards:not(.is-mobile) .workspace-split.mod-left-split .workspace-tabs:last-of-type .workspace-tab-container{padding-bottom:44px}body.layout-cards:not(.is-mobile) .workspace-split.mod-left-split .workspace-sidedock-vault-profile{position:absolute;right:10px;bottom:8px;left:10px;box-sizing:border-box;height:44px;margin:0;padding:6px;padding-right:25px;background:transparent !important;border:0 !important;z-index:10}body.layout-cards:not(.is-mobile) .workspace-split.mod-left-split .workspace-sidedock-vault-profile .workspace-drawer-vault-switcher{height:32px}body.layout-cards:not(.is-mobile).theme-light .workspace-tab-container{border-radius:20px 20px 10px 10px;border:1px solid color-mix(in srgb, var(--primary-color), transparent 80%);margin:8px 10px;background-color:color-mix(in srgb, var(--primary-color), #fff 96%)}body.layout-cards.theme-light .mod-vertical .workspace-tab-header-container{padding-left:20px}body.layout-cards.theme-light .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header-container-inner{align-items:center;justify-content:center;margin:0;margin-top:3px;width:100%;gap:10px;z-index:1}body.layout-cards.theme-light .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header{background:color-mix(in srgb, var(--primary-color), #fff 96%);border-radius:6px;border:1px solid rgba(255, 255, 255, 0.1);box-shadow:0 0 8px rgba(0, 0, 0, 0.15), inset 0 1px 1px rgba(255, 255, 255, 0.15);height:32px;padding:0 !important;transition:400ms, background-color 150ms ease-in-out}body.layout-cards.theme-light .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header.is-active{border:1px solid color-mix(in srgb, var(--primary-color), #fff 70%);box-shadow:0 0 8px color-mix(in srgb, var(--primary-color), transparent 75%), inset 0 1px 1px color-mix(in srgb, var(--primary-color), transparent 75%);background-color:var(--background-primary);font-weight:bold;flex-grow:1.67;max-width:var(--tab-max-width)}body.layout-cards.theme-light .mod-root:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header-inner{padding:0 4px 0 8px;transition:400ms, background-color 150ms ease-in-out, max-width 400ms}body.layout-cards .workspace-tab-header-container .workspace-tab-header::before,body.layout-cards .workspace-tab-header-container .workspace-tab-header::after,body.layout-cards .workspace .mod-root .workspace-tab-header-inner::after{display:none}body.layout-cards:not(.is-phone).theme-light .modal-container.mod-dim .modal,body.layout-cards:not(.is-phone).theme-light .status-bar{border-radius:var(--radius-xl);background:rgba(255, 255, 255, 0.6);border:1px solid rgba(255, 255, 255, 0.4);box-shadow:0 0 8px rgba(0, 0, 0, 0.05), inset 0 1px 1px rgba(255, 255, 255, 0.5);margin:0 5px 5px 5px;transform:translate(0, -5px)}body.layout-cards:not(.is-phone).theme-light .workspace-tabs{background:var(--background-card)}body.layout-cards:not(.is-mobile).theme-dark .workspace-tab-container{border-radius:20px 20px 10px 10px;border:1px solid rgba(255, 255, 255, 0.08);margin:8px 10px;background-color:var(--background-primary);box-shadow:0 2px 6px rgba(0, 0, 0, 0.4)}body.layout-cards.theme-dark .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header{background:rgba(255, 255, 255, 0.03);border-radius:6px;border:1px solid rgba(255, 255, 255, 0.05);box-shadow:none;height:32px;padding:0 !important;transition:400ms, background-color 150ms ease-in}body.layout-cards.theme-dark .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header.is-active{border:1px solid rgba(255, 255, 255, 0.1);box-shadow:0 2px 10px rgba(0, 0, 0, 0.3);background-color:var(--background-secondary);font-weight:bold;flex-grow:1.67;max-width:240px}body.layout-cards.theme-dark .workspace-tab-header.is-active .workspace-tab-header-inner-title{color:var(--text-normal)}body.layout-cards.theme-dark .mod-vertical:not(.mod-left-split):not(.mod-right-split) .workspace-tabs:not(.mod-stacked) .workspace-tab-header-container-inner{align-items:center;justify-content:center;margin:0;margin-top:3px;width:100%;gap:10px}body.layout-cards:not(.is-phone).theme-dark .modal-container.mod-dim .modal,body.layout-cards:not(.is-phone).theme-dark .status-bar{border-radius:var(--radius-xl);background:rgba(30, 30, 30, 0.6);border:1px solid rgba(255, 255, 255, 0.08);box-shadow:0 0 20px rgba(0, 0, 0, 0.5);margin:0 5px 5px 5px;transform:translate(0, -5px)}.community-modal-meta{display:grid;grid-template-areas:"name name name name" "desc desc desc desc" "downloads version author updated" "repo repo repo repo" "buttons buttons buttons buttons";grid-template-columns:minmax(0, 2fr) minmax(0, 2fr) minmax(0, 2fr) minmax(0, 1fr);gap:16px;margin-bottom:0 !important}.community-modal-info-name{grid-area:name;font-size:24px;font-weight:800;color:var(--primary-color);line-height:1.2;margin-bottom:4px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}.flair{font-size:11px;background-color:var(--background-secondary) !important;border:1px solid var(--border-color);color:var(--text-muted) !important;padding:2px 8px;border-radius:50px;text-transform:uppercase;font-weight:bold;letter-spacing:0.5px;top:-2px;position:relative}.flair.mod-pop{color:var(--secondary-color) !important;border-color:var(--secondary-color);background-color:color-mix(in srgb, var(--secondary-color), transparent 90%) !important}.community-modal-info-desc{grid-area:desc;font-size:15px;line-height:1.6;color:var(--text-normal);opacity:0.9;padding-bottom:20px;border-bottom:1px dashed var(--border-color);margin-bottom:8px}.community-modal-info-downloads,.community-modal-info-version,.community-modal-info-author,.community-modal-info-repo{display:flex;flex-direction:column;justify-content:center;gap:4px;padding:12px;background-color:var(--background-secondary);border-radius:8px;font-size:13px;color:var(--text-muted);margin:0 !important;min-width:0}.community-modal-info-downloads{grid-area:downloads}.community-modal-info-version{grid-area:version}.community-modal-info-author{grid-area:author}.community-modal-info-repo{grid-area:repo;grid-column:1 / -1;align-items:flex-start}.community-modal-info-repo + .community-modal-info-repo{grid-area:updated;grid-column:auto;align-items:stretch}@media (max-width:700px){.community-modal-meta{grid-template-areas:"name" "desc" "downloads" "version" "author" "updated" "repo" "buttons";grid-template-columns:1fr}}.community-modal-info-downloads{color:var(--text-normal);font-weight:bold;border:1px solid color-mix(in srgb, var(--primary-color), transparent 80%);background-color:color-mix(in srgb, var(--primary-color), transparent 96%)}.community-modal-info-downloads::before{content:"DOWNLOADS";font-size:10px;font-weight:bold;color:var(--primary-color);opacity:0.7;margin-bottom:4px;letter-spacing:0.5px}.community-modal-info-downloads span{display:flex;align-items:center;gap:6px;font-size:16px}.community-modal-info-downloads svg{width:16px;height:16px;color:var(--primary-color)}.community-modal-info-version::before{content:"VERSION"}.community-modal-info-author::before{content:"AUTHOR"}.community-modal-info-repo::before{content:"REPOSITORY"}.community-modal-info-repo + .community-modal-info-repo::before{content:"UPDATED"}.community-modal-info-version::before,.community-modal-info-author::before,.community-modal-info-repo::before{font-size:10px;font-weight:bold;color:var(--text-muted);opacity:0.6;margin-bottom:2px;display:block}.community-modal-info-author a,.community-modal-info-repo a{color:var(--text-normal);text-decoration:none;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}.community-modal-info-author + .community-modal-info-repo a{color:var(--primary-color);overflow:visible;overflow-wrap:anywhere;text-decoration:underline;text-overflow:clip;white-space:normal}.community-modal-info-author a:hover,.community-modal-info-repo a:hover{color:var(--primary-color);text-decoration:underline}.community-modal-button-container{grid-area:buttons;margin-top:20px;padding-top:20px;border-top:1px dashed var(--border-color);display:flex;gap:10px;flex-wrap:wrap}.community-modal-button-container button{flex:1;justify-content:center}.codeblock-customizer-line-number,.codeblock-customizer-line-number-specific{background:transparent}body.rainbow-folders .nav-folder{--nav-c-pink:#ff7096;--nav-c-cyan:#3db8bf;--nav-c-orange:#f59e0b;--nav-c-green:#11aa63;--nav-c-purple:#A06EB4;--nav-c-red:#aa1141;--nav-c-blue:#1D4E89;--folder-color:var(--text-muted);--nav-item-background-hover:color-mix(in srgb, var(--folder-color), transparent 95%);--background-modifier-active-hover:color-mix(in srgb, var(--primary-color), transparent 95%)}body.rainbow-folders .nav-files-container{--folder-color:var(--primary-color);--nav-item-background-hover:color-mix(in srgb, var(--primary-color), transparent 95%);--background-modifier-active-hover:color-mix(in srgb, var(--primary-color), transparent 90%)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+1){--folder-color:var(--nav-c-pink)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+2){--folder-color:var(--nav-c-cyan)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+3){--folder-color:var(--nav-c-orange)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+4){--folder-color:var(--nav-c-green)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+5){--folder-color:var(--nav-c-purple)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+6){--folder-color:var(--nav-c-red)}body.rainbow-folders .nav-files-container > div > .nav-folder:nth-child(7n+7){--folder-color:var(--nav-c-blue)}body div.nav-files-container.node-insert-event{border-bottom:1px solid color-mix(in srgb, var(--primary-color), transparent 85%) !important}body.rainbow-folders .nav-files-container > div > .nav-folder{margin:0 0 8px 0 !important;padding:0px 0 !important;border-radius:0 8px 8px 0;border-left:4px solid var(--folder-color) !important;transition:background-color 0.2s ease}body.rainbow-folders .nav-folder .nav-folder{border-left:none !important;background-color:transparent !important;margin:0 !important;padding:0 !important;border-radius:0}body.rainbow-folders .nav-folder.is-collapsed{padding-bottom:0 !important}body.rainbow-folders .nav-folder-title{padding:6px 8px !important;margin:1px 0 !important;border-radius:6px;font-weight:500;color:var(--folder-color);display:flex;align-items:center}body.rainbow-folders .nav-folder .nav-folder .nav-folder-title-content{opacity:0.9}body.rainbow-folders .nav-folder-title:hover{background-color:var(--background-modifier-hover)}body.rainbow-folders.folder-icons .nav-folder-collapse-indicator,body.rainbow-folders.folder-icons .nav-folder .collapse-icon{display:none !important}body.rainbow-folders .nav-folder-children{margin-left:14px !important;padding-left:10px !important;border-left:1px solid color-mix(in srgb, var(--folder-color), transparent 70%)}body.rainbow-folders .nav-folder:hover > .nav-folder-children{border-left-color:color-mix(in srgb, var(--folder-color), transparent 40%)}body.rainbow-folders.folder-icons .nav-folder-title-content::before,body.rainbow-folders .nav-file-title-content::before{content:"";display:inline-block;width:16px;height:16px;margin-right:8px;vertical-align:text-bottom;background-color:currentColor;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform 0.2s ease, opacity 0.2s ease}body.rainbow-folders .nav-file-title-content::before{width:14px;height:14px;opacity:0.6}body.rainbow-folders .nav-file-title:hover .nav-file-title-content::before{opacity:0.9}body.rainbow-folders.folder-icons .nav-folder-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z'/%3E%3C/svg%3E");opacity:0.8}body.rainbow-folders.folder-icons .nav-folder:not(.is-collapsed) > .nav-folder-title .nav-folder-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");opacity:1}body.rainbow-folders .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E")}body.rainbow-folders .nav-file-title[data-path$=".png" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".jpg" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".jpeg" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".gif" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".svg" i] .nav-file-title-content::before,body.rainbow-folders .nav-file-title[data-path$=".webp" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E")}body.rainbow-folders .nav-file-title[data-path$=".canvas" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='7' height='9' x='3' y='3' rx='1'/%3E%3Crect width='7' height='5' x='14' y='3' rx='1'/%3E%3Crect width='7' height='9' x='14' y='12' rx='1'/%3E%3Crect width='7' height='5' x='3' y='16' rx='1'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='7' height='9' x='3' y='3' rx='1'/%3E%3Crect width='7' height='5' x='14' y='3' rx='1'/%3E%3Crect width='7' height='9' x='14' y='12' rx='1'/%3E%3Crect width='7' height='5' x='3' y='16' rx='1'/%3E%3C/svg%3E")}body.rainbow-folders .nav-file-title[data-path$=".base" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E")}body.theme-light.rainbow-folders .nav-files-container > div > .nav-folder{background-color:color-mix(in srgb, var(--folder-color), transparent 96%);border-top:1px solid color-mix(in srgb, var(--folder-color), transparent 92%);border-bottom:1px solid color-mix(in srgb, var(--folder-color), transparent 92%);border-right:1px solid color-mix(in srgb, var(--folder-color), transparent 92%)}body.theme-light.rainbow-folders .nav-files-container > div > .nav-folder:hover{background-color:color-mix(in srgb, var(--folder-color), transparent 92%)}body.theme-dark.rainbow-folders .nav-files-container > div > .nav-folder{background-color:color-mix(in srgb, var(--folder-color), transparent 96%);border-top:1px solid color-mix(in srgb, var(--folder-color), transparent 95%);border-bottom:1px solid color-mix(in srgb, var(--folder-color), transparent 95%);border-right:1px solid color-mix(in srgb, var(--folder-color), transparent 95%)}body.theme-dark.rainbow-folders .nav-files-container > div > .nav-folder:hover{background-color:color-mix(in srgb, var(--folder-color), transparent 92%)}body.rainbow-folders .nav-file-title{padding:4px 8px !important;border-radius:6px;color:var(--text-muted)}body.rainbow-folders .nav-file-title:hover{background-color:var(--background-modifier-hover);color:var(--text-normal)}body.rainbow-folders .nav-file-title.is-active{background-color:var(--background-modifier-active-hover);color:var(--primary-color);font-weight:600}body.rainbow-folders .nav-file-title.is-active .nav-file-title-content::before{background-color:var(--primary-color);opacity:1}@media (hover:hover){body.rainbow-folders:not(.is-grabbing) .tree-item-self.is-clickable:hover{color:var(--folder-color);font-weight:bolder}}.nav-files-container > div > .nav-folder{margin:0 0 8px 0 !important;padding:0 !important;border-left:3px solid var(--folder-color) !important;border-radius:0 6px 6px 0;transition:background-color 0.2s ease}.nav-folder .nav-folder{border-left:none !important;background-color:transparent !important;margin:0 !important;padding:0 !important;border-radius:0}.nav-folder.is-collapsed{padding-bottom:0 !important}.nav-folder-title{padding:4px 6px !important;margin:1px 0 !important;border-radius:4px;font-weight:500;color:var(--folder-color);display:flex;align-items:center}.nav-files-container > div > .nav-folder > .nav-folder-title{padding-left:8px !important}.nav-folder .nav-folder .nav-folder-title-content{opacity:0.9}.nav-folder-title:hover{background-color:var(--background-modifier-hover)}body.folder-icons .nav-folder-collapse-indicator,body.folder-icons .nav-folder .collapse-icon{display:none !important}body.folder-icons .nav-folder-title-content::before,.nav-file-title-content::before{content:"";display:inline-block;width:16px;height:16px;margin-right:8px;vertical-align:text-bottom;background-color:currentColor;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform 0.2s ease, opacity 0.2s ease}.nav-file-title-content::before{width:14px;height:14px;opacity:0.6}.nav-file-title:hover .nav-file-title-content::before{opacity:0.9}body.folder-icons .nav-folder-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z'/%3E%3C/svg%3E");opacity:0.8}body.folder-icons .nav-folder:not(.is-collapsed) > .nav-folder-title .nav-folder-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");opacity:1}.nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E")}.nav-file-title[data-path$=".png" i] .nav-file-title-content::before,.nav-file-title[data-path$=".jpg" i] .nav-file-title-content::before,.nav-file-title[data-path$=".jpeg" i] .nav-file-title-content::before,.nav-file-title[data-path$=".gif" i] .nav-file-title-content::before,.nav-file-title[data-path$=".svg" i] .nav-file-title-content::before,.nav-file-title[data-path$=".webp" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E")}.nav-file-title[data-path$=".canvas" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='7' height='9' x='3' y='3' rx='1'/%3E%3Crect width='7' height='5' x='14' y='3' rx='1'/%3E%3Crect width='7' height='9' x='14' y='12' rx='1'/%3E%3Crect width='7' height='5' x='3' y='16' rx='1'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='7' height='9' x='3' y='3' rx='1'/%3E%3Crect width='7' height='5' x='14' y='3' rx='1'/%3E%3Crect width='7' height='9' x='14' y='12' rx='1'/%3E%3Crect width='7' height='5' x='3' y='16' rx='1'/%3E%3C/svg%3E")}.nav-file-title[data-path$=".base" i] .nav-file-title-content::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E")}.nav-file-title{padding:4px 8px !important;border-radius:6px;color:var(--text-muted)}.nav-file-title:hover{background-color:var(--background-modifier-hover);color:var(--text-normal)}.nav-file-title.is-active{background-color:var(--background-modifier-active-hover);color:var(--primary-color);font-weight:600}.nav-file-title.is-active .nav-file-title-content::before{background-color:var(--primary-color);opacity:1}@media (hover:hover){body:not(.is-grabbing) .tree-item-self.is-clickable:hover{color:var(--folder-color);font-weight:bolder}}.codeblock-customizer-active-line-highlight .cm-active, .codeblock-customizer-active-line-highlight-editor .cm-active{background-color:color-mix(in srgb, var(--primary-color) , transparent 95%)!important} \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/.obsidian/workspace.json b/mengyanote-backend/data/mengyanote/.obsidian/workspace.json index 4d09696..4afb551 100644 --- a/mengyanote-backend/data/mengyanote/.obsidian/workspace.json +++ b/mengyanote-backend/data/mengyanote/.obsidian/workspace.json @@ -7,38 +7,22 @@ "id": "df67c67fc6eede4f", "type": "tabs", "children": [ - { - "id": "d2bcc713b2622c69", - "type": "leaf", - "state": { - "type": "markdown", - "state": { - "file": "计算机网络/计算机网络期末考试综合题简单论述.md", - "mode": "source", - "source": true, - "backlinks": false - }, - "icon": "lucide-file", - "title": "计算机网络期末考试综合题简单论述" - } - }, { "id": "2e06118e2383ad3d", "type": "leaf", "state": { "type": "markdown", "state": { - "file": "树萌芽の小本本/账号合集/Grok账号.md", + "file": "树萌芽の小本本/账号合集/CloudFlare账号.md", "mode": "source", "source": false, "backlinks": false }, "icon": "lucide-file", - "title": "Grok账号" + "title": "CloudFlare账号" } } - ], - "currentTab": 1 + ] } ], "direction": "vertical" @@ -111,13 +95,13 @@ "state": { "type": "outline", "state": { - "file": "树萌芽の小本本/账号合集/Grok账号.md", + "file": "树萌芽の小本本/账号合集/CloudFlare账号.md", "followCursor": false, "showSearch": false, "searchQuery": "" }, "icon": "lucide-list", - "title": "Grok账号 的大纲" + "title": "CloudFlare账号 的大纲" } } ] @@ -138,42 +122,42 @@ }, "active": "2e06118e2383ad3d", "lastOpenFiles": [ - "临时/cursor半价.md", - "树萌芽の小本本/账号合集/Grok账号.md", - "临时/浏览器更换默认字体.md", - "AI/提示词工程/运维部署/Dokcer部署流程.md", - "AI/提示词工程/AI绘图/绘画网站软件logo图标.md", - "AI/提示词工程/AI绘图/AI绘画提示词.md", - "AI/提示词工程/AI绘图/ai换装提示词.md", - "MarkDown/树萌芽のGithub主页.md", - "实习求职/简历/Golang后端开发.md", - "MarkDown/未命名.md", - "树萌芽の小本本/账号合集/CloudFlare账号.md", - "树萌芽の小本本/账号合集/Github账号.md", - "编程语言/前端/代码片段/代码片段-特殊HelloWorld输出.md", - "编程语言/前端/代码片段/代码片段-标准HelloWorld输出.md", - "AI/提示词工程/Windows开发/开发Windows软件细节.md", - "AI/提示词工程/前端开发/前端随机背景图.md", - "AI/提示词工程/前端开发/前端全局字体样式提示词.md", - "AI/提示词工程/前端开发/前端网站图标获取方式.md", - "前后端项目env环境配置解析.md", - "AI/提示词工程/后端开发/后端API开发标准规范.md", - "AI/提示词工程/后端开发/后端API接口根路径说明.md", - "AI/提示词工程/后端开发/后端API部署成docker容器.md", - "Windows/刷新浏览器和系统DNS缓存.md", - "鉴政/女权主义/好姐妹介绍.md", - "鉴政/中国社会主要矛盾演变梳理(1840年至今).md", - "AI/提示词工程/AI绘图/商品封面图生成.md", - "临时/未命名", - "AI/提示词工程/角色扮演", - "AI/提示词工程/后端开发/后端由json更改为SQLite储存", - "算法与数据结构/LeetCode热题100", - "量化投资", - "数据库/RabbitMQ", - "技术原理解析/Golang", - "实习求职/面试经历/树萌芽の面试经历", - "实习求职/术语科普", - "实习求职/面试经历/Golang后端", + "实习求职/项目经历/MengyaNoteRAG/mengya-rag项目简介.md", + "实习求职/项目经历/SproutClaw/SproutClaw的工作流程是react吗,是否有plan-execute模式.md", + "实习求职/项目经历/MengyaNoteRAG/未命名", + "实习求职/项目经历/MengyaNoteRAG", + "实习求职/项目经历/SproutClaw/SproutClaw的上下文工程详情.md", + "实习求职/项目经历/SproutClaw/SproutClaw的MCP工具应用情况.md", + "实习求职/项目经历/SproutClaw/SproutClaw简介.md", + "实习求职/通用面试八股/Agent面试八股.md", + "实习求职/项目经历/MengyaStore", + "实习求职/项目经历/SproutGate", + "实习求职/项目经历/SproutClaw", + "面试求职", + "实习求职/SQL题", + "实习求职/项目经历", + "技术原理解析/项目分析/LocalSend.md", + "实习求职/面试经历/树萌芽の面试经历/2026.6.20豆包模拟面试-1.md", + "技术原理解析/项目分析/SproutClaw", + "临时/八股/栈与堆:概念、区别及内存管理详解.md", + "实习求职/面试经历/树萌芽の面试经历/2026.6.18深势科技Golang后端一面.md", + "AI/提示词工程/角色扮演/模拟后端AI开发面试者系统提示词.md", + "临时/八股/Redis底层数据结构.md", + "实习求职/面试经历/Java后端开发/腾讯/腾讯ieg后端日常实习一二三面面经.md", + "实习求职/面试经历/Java后端开发/2026年4月13日字节二面记录.md", + "实习求职/面试经历/Java后端开发/2026年3月23日三面.md", + "实习求职/面试经历/Java后端开发/2026年3月19日二面.md", + "实习求职/面试经历/Java后端开发/腾讯/腾讯IEG后台开发日常实习二面.md", + "实习求职/面试经历/Java后端开发/腾讯", + "实习求职/面试经历/Java后端开发/字节/字节跳动TikTok后端开发日常实习一面面经.md", + "实习求职/面试经历/Java后端开发/字节/字节后端开发一面面经.md", + "实习求职/面试经历/Java后端开发/字节/字节国际支付二面.md", + "实习求职/面试经历/Java后端开发/字节/某字节二面面经.md", + "实习求职/面试经历/Golang后端开发/字节/✅某佬面试经历.md", + "实习求职/面试经历/通用后端开发/6.4 JD YOUNG后端开发一面凉经.md", + "实习求职/面试经历/Golang后端开发/字节/✅字节Agent中台一面凉经.md", + "实习求职/面试经历/Golang后端开发/字节/✅Go后端开发-字节一面.md", + "实习求职/树萌芽の简历/Golang后端开发.md", "Pasted image 20260324211445.png", "Pasted image 20260325202027.png", "Pasted image 20260324211458.png", diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端全局字体样式提示词.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端全局字体样式提示词.md index f69cc1a..b11c37e 100644 --- a/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端全局字体样式提示词.md +++ b/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端全局字体样式提示词.md @@ -1,3 +1,4 @@ +把网站全局字体改成鹜霞文楷等宽字体,尽可能使用国内外都能加载使用的字体cdn 前端网站默认字体栈约定: - 有网:默认使用思源黑体,尽量使用国内外都能正常加载的字体CDN diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端构建分离网页版和桌面版.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端构建分离网页版和桌面版.md new file mode 100644 index 0000000..e1a14a3 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端构建分离网页版和桌面版.md @@ -0,0 +1,3 @@ +把当前项目的前端构建命令npm run build同时构建出两个版本dist和dist-desketop, +dist版本前端请求后端API继续使用原来的网页相对路径,dist-desketop版本我要使用tauri等框架构建出桌面版软件 +所以让前端请求使用全局路径,比如项目的域名web2app.smyhub.com/api \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端网页做成PWA应用.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端网页做成PWA应用.md new file mode 100644 index 0000000..b547274 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端网页做成PWA应用.md @@ -0,0 +1 @@ +把当前项目的前端网页做成PWA标准应用格式,并添加PWA应用自动提示更新功能 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端随机背景图.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端随机背景图.md index f9d4687..37abeb7 100644 --- a/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端随机背景图.md +++ b/mengyanote-backend/data/mengyanote/AI/提示词工程/前端开发/前端随机背景图.md @@ -1 +1 @@ -添加前端网站统一随机背景图 随机背景图API请使用: https://randbg.api.smyhub.com 设置背景高斯模糊效果为10% \ No newline at end of file +添加前端网站统一随机背景图 随机背景图API请使用: https://randbg.smyhub.com 设置背景高斯模糊效果为10% \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/开发通用提示词/开源项目编写博客介绍文章.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/开发通用提示词/开源项目编写博客介绍文章.md new file mode 100644 index 0000000..507fd15 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/AI/提示词工程/开发通用提示词/开源项目编写博客介绍文章.md @@ -0,0 +1,5 @@ +帮我给我的这个开源项目写一个篇markdown格式的博客文章, +要求文笔真实干练不啰嗦地介绍这个开源项目 +相关信息: +项目开源地址:https://github.com/shumengya/randbg-api +项目在线地址:https://randbg.smyhub.com diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/开发通用提示词/项目完善上传Github.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/开发通用提示词/项目完善上传Github.md new file mode 100644 index 0000000..12cd2c4 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/AI/提示词工程/开发通用提示词/项目完善上传Github.md @@ -0,0 +1,4 @@ +给我完善这个项目细节 我准备开源到github ; +你帮我把readme和其他相关的开源完善,还有敏感信息不能上传到github ; +我的github仓库是shumengya/ ; +项目在线体验网站:https:// \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/角色扮演/模拟算法大师.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/角色扮演/模拟算法大师.md index fc91ab2..b99e3b2 100644 --- a/mengyanote-backend/data/mengyanote/AI/提示词工程/角色扮演/模拟算法大师.md +++ b/mengyanote-backend/data/mengyanote/AI/提示词工程/角色扮演/模拟算法大师.md @@ -4,32 +4,23 @@ 讲解风格:耐心细致,从最直观的解法切入,循序渐进引导学习者理解算法思想与实现。 --- - ## 行为规则 - 1. **无需打招呼**,收到题目后直接输出内容,第一行必须是标签行。 2. 若题目描述不完整,礼貌询问补充,或基于已知原题直接作答。 3. 禁止使用"显然""很容易""不难发现"等跳过关键步骤的措辞。 4. 始终假设用户只掌握 Python 基础(变量、循环、列表、字典、函数)。 --- - ## 输出结构(严格按顺序) - ### 第一行:标签 格式固定为: - **标签**:[标签1]、[标签2]、[标签3] - - 提取本题核心算法 / 数据结构,3~4 个,中文顿号分隔。 - 示例:`**标签**:数组、哈希表、双指针` --- - ### 正文结构 - # [题目名称] - ## 题目理解 用自己的话重新描述题意(不照搬原文),确保零基础用户看懂: - 输入是什么?输出是什么? @@ -37,15 +28,11 @@ - 用一个具体小例子辅助说明。 --- - ## 解法一:[名称](最简单解法,必须首位) - > 原则:优先选最直观的暴力解法,让用户先看懂逻辑,效率次之。 - ### 思路 - 解释"为什么想到用这种方法" - 用文字逐步描述解题过程,不要跳步 - ### 代码 ​```python class Solution: @@ -53,12 +40,10 @@ class Solution: # 每一个关键操作都写行内注释 # 第一次出现的内置函数/语法(如 enumerate、zip)必须注释说明用法 ... - # 测试示例 sol = Solution() print(sol.methodName(...)) # 期望输出:... ​``` - ### 复杂度分析 | 维度 | 复杂度 | 说明 | |------|--------|------| @@ -72,22 +57,16 @@ print(sol.methodName(...)) # 期望输出:... - 目标值不存在(若题目保证有解则注明) --- - ## 解法二:[名称](优化解法,视题目情况提供) - > 说明本解法相对解法一的改进点(时间 / 空间 / 代码简洁度)。 - ### 思路 (同上,详细描述) - ### 代码 (同上,含注释和测试) - ### 复杂度分析 (同上,并与解法一对比) --- - ## 解法对比总结(有多解法时必须提供) | 解法 | 时间复杂度 | 空间复杂度 | 推荐场景 | @@ -96,13 +75,10 @@ print(sol.methodName(...)) # 期望输出:... | 解法二:哈希表 | O(n) | O(n) | 面试首选 | --- - ## 注释规范(代码内) - 以下情形**必须**写注释: - 每个循环的目的 - 条件判断的含义 - 第一次出现的 Python 内置函数或语法糖 - 关键变量的含义(用 `# 变量名:含义` 格式) - 好的,现在你将等待用户向你发送算法题目,如果你已经准备好,请回复"我已准备好,请发送算法题目" \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具].md b/mengyanote-backend/data/mengyanote/AI/提示词工程/项目初始化模板/CloudFlare Worker项目.md similarity index 100% rename from mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具].md rename to mengyanote-backend/data/mengyanote/AI/提示词工程/项目初始化模板/CloudFlare Worker项目.md diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/项目初始化模板/React和Vite前端+Golang和Gin后端+SQLite储存.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/项目初始化模板/React和Vite前端+Golang和Gin后端+SQLite储存.md new file mode 100644 index 0000000..e69de29 diff --git a/mengyanote-backend/data/mengyanote/AI/提示词工程/项目初始化模板/React和Vite前端+Python和Flask后端+SQLite储存.md b/mengyanote-backend/data/mengyanote/AI/提示词工程/项目初始化模板/React和Vite前端+Python和Flask后端+SQLite储存.md new file mode 100644 index 0000000..e69de29 diff --git a/mengyanote-backend/data/mengyanote/AI/未命名.md b/mengyanote-backend/data/mengyanote/AI/未命名.md index 1ead600..e0e98ce 100644 --- a/mengyanote-backend/data/mengyanote/AI/未命名.md +++ b/mengyanote-backend/data/mengyanote/AI/未命名.md @@ -38,6 +38,4 @@ - 强调生产就绪:状态管理、Human-in-the-Loop、安全 Guardrails、Observability。 - Agent 从实验原型走向“数字员工”,重点通过 Skills 标准化业务能力。 -**文档精要**:2026 年应用层开发核心是 **Role-based Multi-Agent + Skills 工程 + MCP/A2A 集成**,目标是构建可靠、可落地、可协作的业务 Agent 系统。 - -需要输出 Markdown 版本、添加具体 Skill 示例,或导出为特定格式吗? \ No newline at end of file +**文档精要**:2026 年应用层开发核心是 **Role-based Multi-Agent + Skills 工程 + MCP/A2A 集成**,目标是构建可靠、可落地、可协作的业务 Agent 系统。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/CloudFlare/Cloudflare KV、D1、R2 三种存储服务的核心差异对比.md b/mengyanote-backend/data/mengyanote/CloudFlare/Cloudflare KV、D1、R2 三种存储服务的核心差异对比.md index 0533430..b708ad5 100644 --- a/mengyanote-backend/data/mengyanote/CloudFlare/Cloudflare KV、D1、R2 三种存储服务的核心差异对比.md +++ b/mengyanote-backend/data/mengyanote/CloudFlare/Cloudflare KV、D1、R2 三种存储服务的核心差异对比.md @@ -1,17 +1,17 @@ -| 维度 | **Workers KV** (键值存储) | **D1** (轻量级 SQL 数据库) | **R2** (对象/Blob 存储) | -|---------------|---------------------------|-----------------------------|-------------------------| -| **数据模型** | 简单 Key-Value 对(字符串或二进制) | 关系型(SQLite 语法,表、行、列、JOIN) | 非结构化对象(文件、图片、视频等,S3 兼容) | -| **适用场景** | 配置数据、会话、A/B 测试、路由元数据、高频读的简单缓存 | 用户资料、订单、产品列表、关系型业务数据、需要复杂查询的场景 | 图片/视频/大文件、ML 数据集、日志、用户上传文件、静态资源 | -| **查询能力** | 只支持按 Key 获取、按前缀 List(无复杂查询) | **完整 SQL**(SELECT、JOIN、事务、聚合等) | 按 Key/metadata 访问,无原生内容查询(可配合 R2 SQL 做分析) | -| **一致性** | **最终一致性**(eventually consistent) | **强一致性**(strongly consistent,支持事务) | **强一致性**(每个对象) | -| **性能特点** | 极低延迟(热 Key <10ms,全球边缘缓存)
适合**读重**场景(千级 RPS) | 同数据中心零延迟绑定 + 读复制全球加速
适合读重轻量应用 | 适合大对象,延迟比 KV/D1 高,但吞吐强 | -| **大小限制** | 单个 Value ≤25 MiB
免费 1GB,付费无限 | **单库**免费 500MB / 付费 10GB
账号总存储免费 5GB / 付费 1TB
最多 50,000 个库(付费) | **单个对象** ≤5 TiB
存储完全无限,桶最多 100 万个 | -| **写限制** | 同 Key 每秒最多 1 次写 | 行写入有配额(免费 10万行/天) | 同 Key 每秒最多 1 次并发写 | -| **定价(付费计划)** | 存储:$0.50/GB-月
读:$0.50/百万次
写/删/列:$5/百万次 | 存储:$0.75/GB-月(前 5GB 包含)
行读:$0.001/百万行
行写:$1/百万行
**无出口费** | 存储:$0.015/GB-月(超便宜!)
Class A 操作:$4.50/百万
Class B 操作:$0.36/百万
**完全免费出口费** | -| **免费额度** | 读 10万/天,写 1000/天,1GB | 读 500万行/天,写 10万行/天,5GB | 10GB 存储 + 110万操作/月 + 无限出口 | -| **出口(Egress)** | 不涉及下载场景 | **完全免费** | **完全免费**(最大卖点) | +| 维度 | **Workers KV** (键值存储) | **D1** (轻量级 SQL 数据库) | **R2** (对象/Blob 存储) | +| -------------- | ---------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | +| **数据模型** | 简单 Key-Value 对(字符串或二进制) | 关系型(SQLite 语法,表、行、列、JOIN) | 非结构化对象(文件、图片、视频等,S3 兼容) | +| **适用场景** | 配置数据、会话、A/B 测试、路由元数据、高频读的简单缓存 | 用户资料、订单、产品列表、关系型业务数据、需要复杂查询的场景 | 图片/视频/大文件、ML 数据集、日志、用户上传文件、静态资源 | +| **查询能力** | 只支持按 Key 获取、按前缀 List(无复杂查询) | **完整 SQL**(SELECT、JOIN、事务、聚合等) | 按 Key/metadata 访问,无原生内容查询(可配合 R2 SQL 做分析) | +| **一致性** | **最终一致性**(eventually consistent) | **强一致性**(strongly consistent,支持事务) | **强一致性**(每个对象) | +| **性能特点** | 极低延迟(热 Key <10ms,全球边缘缓存)
适合**读重**场景(千级 RPS) | 同数据中心零延迟绑定 + 读复制全球加速
适合读重轻量应用 | 适合大对象,延迟比 KV/D1 高,但吞吐强 | +| **大小限制** | 单个 Value ≤25 MiB
免费 1GB,付费无限 | **单库**免费 500MB / 付费 10GB
账号总存储免费 5GB / 付费 1TB
最多 10个库(免费) 50,000 个库(付费) | **单个对象** ≤5 TiB(免费版10GB)
存储完全无限,桶最多 100 万个 | +| **写限制** | 同 Key 每秒最多 1 次写 | 行写入有配额(免费 10万行/天) | 同 Key 每秒最多 1 次并发写 | +| **定价(付费计划)** | 存储:$0.50/GB-月
读:$0.50/百万次
写/删/列:$5/百万次 | 存储:$0.75/GB-月(前 5GB 包含)
行读:$0.001/百万行
行写:$1/百万行
**无出口费** | 存储:$0.015/GB-月(超便宜!)
Class A 操作:$4.50/百万
Class B 操作:$0.36/百万
**完全免费出口费** | +| **免费额度** | 读 10万/天,写 1000/天,1GB | 读 500万行/天,写 10万行/天,5GB | 10GB 存储 + 110万操作/月 + 无限出口 | +| **出口(Egress)** | 不涉及下载场景 | **完全免费** | **完全免费**(最大卖点) | ### 快速选择指南 - **选 KV**:需要全球超快读取的简单数据(如配置、计数器、session),不想写 SQL。 diff --git a/mengyanote-backend/data/mengyanote/Git/Git提交规范.md b/mengyanote-backend/data/mengyanote/Git/Git提交规范.md new file mode 100644 index 0000000..3b397a7 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/Git/Git提交规范.md @@ -0,0 +1,43 @@ +### 1. 主流分支策略(最核心的部分) +大型公司很少用最简单的“所有人直接推 main”,而是根据团队规模、发布频率和合规要求选择以下策略: + +| 策略 | 适用场景 | 核心分支 | 特点 | 代表公司/团队 | +|------|----------|----------|------|--------------| +| **GitFlow**(经典) | 大型团队、计划发布周期(如月度/季度)、需要维护多个版本 | `main`(生产)、`develop`(开发主线)、`feature/*`、`release/*`、`hotfix/*` | 结构清晰、适合复杂项目,但分支生命周期长,合并冲突较多 | 传统企业、金融、需要 LTS 版本的产品 | +| **GitHub Flow**(简化) | Web/云服务、中大型团队、频繁部署 | `main` + 短生命周期 `feature/*` 或 `issue-xxx` | 一切通过 PR,所有变更必须 Review | 很多互联网公司、开源项目 | +| **Trunk-Based Development (TBD,主干开发)** | 极大规模团队、高频 CI/CD、微服务 | 主要一个 `main/trunk`,极短分支(几小时~几天) | 最现代,强调 Feature Flag + 小步快跑,合并冲突最少 | Google、Meta、字节跳动(部分)、Netflix 等 | + +**当前趋势(2025-2026)**:越来越多大型公司向 **Trunk-Based** 或其变体迁移,尤其是采用微服务 + 完善的 CI/CD + Feature Toggle 的团队。因为 GitFlow 的长期分支在百人以上团队中容易导致“分支地狱”。 +### 2. 仓库形态 +- **Monorepo(单仓)**:一个巨大仓库放多个服务/模块(如 Google、字节、Meta)。好处是原子提交、统一依赖管理;坏处是仓库巨大,需要特殊工具(Bazel、Nx 等)。 +- **Multi-repo(多仓)**:每个服务/业务域一个仓库。更常见于传统大型企业和微服务初期。 +- 混合模式:核心业务 Monorepo + 外围服务 Multi-repo。 +### 3. 权限分配(企业级重点) +正规大公司不会给所有人 `push` 到 `main` 的权限,通常分层管理: +- **Owner / Admin**:项目负责人、架构师、Tech Lead(极少数人) +- **Maintainer**:可合并 PR、管理分支、设置保护规则 +- **Developer / Member**:可创建分支、提 PR、Review 代码(主流权限) +- **Read-only / Guest**:测试、PM、外部合作方 +**常见保护规则(Protected Branch)**: +- `main` / `master`:**必须 PR + 至少 2 人 Review + CI 通过 + 特定角色才能合并** +- `develop`(如果有):可放宽但仍需 Review +- `release/*`:严格控制 +- 强制线性历史(Require linear history)、禁止 force push +**平台层面**: +- **GitHub Enterprise** / **GitLab** / **Gitee 企业版** / **Azure DevOps** / **Bitbucket** 最常用。 +- 通过 **Teams / Group** 批量分配权限(推荐)。 +- Code Owner 机制:特定目录必须特定团队 Review。 +### 4. 典型开发流程(大型公司标准) +1. **领任务** → 从 `main` 或 `develop` 拉 **短分支**(`feature/xxx` 或 `user/你的名字/功能`) +2. **本地开发 + 自测** → 频繁 commit(小步提交) +3. **提 PR/MR** → 必须关联 Issue/Task,写好描述 + 测试用例 +4. **自动化检查**:CI(单元测试、代码扫描、构建)必须通过 +5. **Code Review**(至少 1-2 人) +6. **合并** → 自动或手动部署到测试/预发/生产 +7. **Hotfix**:直接从 `main` 拉 hotfix 分支,紧急修复后双合并(main + develop) +### 额外最佳实践(大公司都在做) +- **Commit Message 规范**:Conventional Commits(`feat:`、`fix:`、`chore:` 等) +- **分支命名规范**:`feature/模块-功能`、`bugfix/xxx`、`hotfix/xxx` +- **Feature Flag**:大型团队必备,避免长分支 +- **代码所有者(CODEOWNERS)** 文件 +- **定期 Rebase / Squash Merge** 保持历史干净 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/Linux/linux 如何快速删除一个目录下的一百万个文件.md b/mengyanote-backend/data/mengyanote/Linux/linux 如何快速删除一个目录下的一百万个文件.md new file mode 100644 index 0000000..8f12940 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/Linux/linux 如何快速删除一个目录下的一百万个文件.md @@ -0,0 +1,89 @@ + +--- + +### 方法对比 + +**❌ 慢的方式** + +```bash +rm -rf /path/to/dir/* # shell 展开百万参数,直接OOM或报错 +``` + +--- + +### ✅ 推荐方案(从快到慢排序) + +**1. 直接删除目录后重建(最快)** + +```bash +rm -rf /path/to/dir && mkdir /path/to/dir +``` + +> 整个目录作为一个单元删除,OS 直接释放 inode,无需逐一处理文件,**秒级完成**。 + +--- + +**2. rsync 清空目录(保留目录本身)** + +```bash +mkdir /tmp/empty_dir +rsync -a --delete /tmp/empty_dir/ /path/to/dir/ +``` + +> 利用 rsync 的增量同步机制,不走 shell 参数展开,**批量高效**。 + +--- + +**3. find + delete(通用,稳健)** + +```bash +find /path/to/dir -type f -delete +``` + +> `find` 逐一遍历不展开通配符,`-delete` 比 `-exec rm` 快得多(无 fork 开销)。 + +--- + +**4. find + xargs 并行删除** + +```bash +find /path/to/dir -type f | xargs -P 8 -n 10000 rm -f +``` + +> `-P 8` 开 8 个并行进程,`-n 10000` 每批处理1万个文件,充分利用多核。 + +--- + +**5. Python/Perl 脚本(绕过 shell 限制)** + +```python +import os +for f in os.scandir('/path/to/dir'): + os.unlink(f.path) +``` + +> `os.scandir` 是系统调用级别的遍历,比 shell glob 高效。 + +--- + +### 面试加分点 + +|知识点|说明| +|---|---| +|**inode 耗尽**|百万小文件会耗尽 inode,`df -i` 检查| +|**目录 entry 锁**|删除时目录会加锁,串行删除是瓶颈| +|**page cache**|大量删除会触发 dentry/inode cache 回收,影响系统| +|**文件系统差异**|ext4 / xfs 对大目录处理性能不同,xfs 更优| +|**软删除**|生产环境可先 `mv` 到待删目录,异步清理,不影响业务| + +--- + +### 最佳实践总结 + +``` +能删目录重建 → rm -rf dir && mkdir dir # 首选 +只能清空目录 → rsync --delete 或 find -delete # 次选 +需要并行加速 → xargs -P 多进程 # 大量文件时 +``` + +**根本思路**:避免 shell 参数展开,减少 fork/exec 系统调用,尽量利用批量或目录级操作。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/MarkDown/树萌芽のGithub主页.md b/mengyanote-backend/data/mengyanote/MarkDown/树萌芽のGithub主页.md index bbddd0f..f20a59c 100644 --- a/mengyanote-backend/data/mengyanote/MarkDown/树萌芽のGithub主页.md +++ b/mengyanote-backend/data/mengyanote/MarkDown/树萌芽のGithub主页.md @@ -3,50 +3,50 @@
-# 🔍 你好,我是 **树萌芽** 🌱 +# 🔍 你好,我是 **树萌芽** **一个喜欢捣鼓各种奇奇怪怪的玩意的人**
avatar
--- -## ✨ 关于我(About Me) -- **昵称**:树萌芽 🌿 -- **定位**:Full-Stack / Backend / DevOps ⚙️ -- **简介**:努力学习,努力生活!💪 +## 关于我(About Me) +- **昵称**:树萌芽 +- **定位**:Full-Stack / Backend / DevOps +- **简介**:努力学习,努力生活! --- -## 🛠 技术栈(Tech Stack) -🐍 Golang-Gin · Python-Flask · Java-SpringBoot -☕ MySQL · MongoDB · SQLite · Redis -🐳 Docker · LXC -🐧 Debian · Ubuntu +## 技术栈(Tech Stack) +Golang-Gin · Python-Flask · Java-SpringBoot +MySQL · MongoDB · SQLite · Redis +Docker · LXC +Debian · Ubuntu --- -## 📦 精选项目(Selected Projects) +## 精选项目(Selected Projects) -| 项目名称 | 项目简介 | 项目地址 | 开源地址 | 技术栈 | -| ------------ | -------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------- | -| **萌芽主页** | 简单好看的个人主页 | [www.shumengya.top](https://www.shumengya.top) | | Python Flask + React + Docker | -| **萌芽笔记** | Obsidian MarkDown笔记库 | [note.shumengya.top](https://note.shumengya.top) | | Python Flask + React + Docker | -| **萌芽作品集** | 个人作品合集 | [work.shumengya.top](https://work.shumengya.top) | | Golang Gin + React + Docker | -| **万象口袋** | 一站式跨平台工具合集 | [infogenie.shumengya.top](https://infogenie.shumengya.top) | [github.com/shumengya/InfoGenie](https://github.com/shumengya/InfoGenie) | Golang Gin + React + Docker | -| **萌芽短链** | 短链接分享工具 | [short.shumengya.top](https://short.shumengya.top) | | Python Flask + React + Docker | -| **萌芽漂流瓶** | 个人小玩具 | [bottle.shumengya.top](https://bottle.shumengya.top) | | Python Flask + React + Docker | -| **萌芽SSH** | 网页SSH连接工具 | [ssh.shumengya.top](https://ssh.shumengya.top) | | Golang Gin + React + Docker | -| **萌芽小店** | 轻量级商城系统 | [store.shumengya.top](https://store.shumengya.top) | [github.com/shumengya/mengyastore](https://github.com/shumengya/mengyastore) | Golang Gin + React + Docker | -| **萌芽导航** | 浏览器网站导航 | [nav.smyhub.com](https://nav.smyhub.com) | | CloudFlare Worker + D1 SQL | -| **萌芽账户认证中心** | 自制软件作品统一账户认证中心 | [auth.shumengya.top](https://auth.shumengya.top) | | Golang Gin + React + Docker | -| **萌芽Ping** | 网站监控面板 | [ping.shumengya.top](https://ping.shumengya.top) | | Golang Gin + React + Docker | -| **萌芽VPS监控** | 服务器监控面板 | [monitor.shumengya.top](https://monitor.shumengya.top) | | Golang Gin + React + Docker | -| **萌芽博客** | 极客轻量级极简博客 | [blog.smyhub.com](https://blog.smyhub.com) | | CloudFlare Worker + D1 SQL | +| 项目名称 | 项目简介 | 项目地址 | 开源地址 | 技术栈 | +| ------------ | ---------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------- | +| **萌芽主页** | 简单好看的个人主页 | [www.shumengya.top](https://www.shumengya.top) | | Python Flask + React + Docker | +| **萌芽笔记** | 树萌芽のObsidian 笔记库 | [note.shumengya.top](https://note.shumengya.top) | | Python Flask + React + Docker | +| **萌芽作品集** | 树萌芽の个人作品合集 | [work.shumengya.top](https://work.shumengya.top) | | Golang Gin + React + Docker | +| **万象口袋** | 一站式跨平台工具合集 | [infogenie.shumengya.top](https://infogenie.shumengya.top) | [github.com/shumengya/InfoGenie](https://github.com/shumengya/InfoGenie) | Golang Gin + React + Docker | +| **萌芽短链** | 短链接分享工具 | [short.shumengya.top](https://short.shumengya.top) | | Python Flask + React + Docker | +| **萌芽漂流瓶** | 个人小玩具 | [bottle.shumengya.top](https://bottle.shumengya.top) | | Python Flask + React + Docker | +| **萌芽SSH** | 网页SSH连接工具 | [ssh.shumengya.top](https://ssh.shumengya.top) | | Golang Gin + React + Docker | +| **萌芽小店** | 轻量级商城系统 | [store.shumengya.top](https://store.shumengya.top) | [github.com/shumengya/mengyastore](https://github.com/shumengya/mengyastore) | Golang Gin + React + Docker | +| **萌芽导航** | 浏览器网站导航 | [nav.smyhub.com](https://nav.smyhub.com) | | CloudFlare Worker + D1 SQL | +| **萌芽账户认证中心** | 自制软件作品统一账户认证中心 | [auth.shumengya.top](https://auth.shumengya.top) | | Golang Gin + React + Docker | +| **萌芽Ping** | 网站监控面板 | [ping.shumengya.top](https://ping.shumengya.top) | | Golang Gin + React + Docker | +| **萌芽VPS监控** | 服务器监控面板 | [monitor.shumengya.top](https://monitor.shumengya.top) | | Golang Gin + React + Docker | +| **萌芽小窝** | 极客轻量级极简博客 | [blog.smyhub.com](https://blog.smyhub.com) | | CloudFlare Worker + D1 SQL | --- -## 📫 联系方式(Contact) -- 📧 **联系邮箱:**[mail@smyhub.com](mailto:mail@smyhub.com) -- 🌐 **个人主页:**[smyhub.com](https://smyhub.com) -- 🐙 **GitHub主页:**[github.com/shumengya](https://github.com/shumengya) -- 📝 **个人博客:**[blog.smyhub.com](https://blog.smyhub.com) -- 💬 **闲聊说说:**[memos.shumengya.top](https://memos.shumengya.top) +## 联系方式(Contact) +- **联系邮箱:**[mail@smyhub.com](mailto:mail@smyhub.com) +- **个人主页:**[smyhub.com](https://smyhub.com) +- **GitHub主页:**[github.com/shumengya](https://github.com/shumengya) +- **个人博客:**[blog.smyhub.com](https://blog.smyhub.com) +- **闲聊说说:**[memos.shumengya.top](https://memos.shumengya.top) --- \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/量化投资/比特币实时官方API接口.md b/mengyanote-backend/data/mengyanote/Web3区块链/BTC实时官方API接口.md similarity index 79% rename from mengyanote-backend/data/mengyanote/量化投资/比特币实时官方API接口.md rename to mengyanote-backend/data/mengyanote/Web3区块链/BTC实时官方API接口.md index 8ce39a5..dad17ce 100644 --- a/mengyanote-backend/data/mengyanote/量化投资/比特币实时官方API接口.md +++ b/mengyanote-backend/data/mengyanote/Web3区块链/BTC实时官方API接口.md @@ -1,27 +1,27 @@ ### 1. **Binance(最推荐,交易所官方现货价格)** - **最新单一价格**: - `https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT` + `https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT` - **24小时完整Ticker(含涨跌幅、高低价等)**: - `https://api.binance.com/api/v3/ticker/24hr?symbol=BTCUSDT` - + `https://api.binance.com/api/v3/ticker/24hr?symbol=BTCUSDT` +- **U本位永续合约24小时完整Ticcker** + `https://fapi.binance.com/fapi/v1/ticker/24hr?symbol=BTCUSDT` **官方文档**:https://developers.binance.com/docs/binance-spot-api-docs/rest-api/market-data-endpoints - +--- ### 2. **OKX(交易所官方)** - **Ticker接口**: `https://www.okx.com/api/v5/market/ticker?instId=BTC-USDT` - **官方文档**:https://www.okx.com/docs-v5/en/ - +--- ### 3. **CoinGecko(最受欢迎的聚合官方API,无需Key)** - **简单价格**(USD,BTC与USDT价格极接近): `https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd` - **比特币完整信息**(含价格、24h变化等): `https://api.coingecko.com/api/v3/coins/bitcoin` - **官方文档**:https://docs.coingecko.com/ +--- ### 4. **Bybit(交易所官方,现货)** - **Tickers接口**(支持BTCUSDT): `https://api.bybit.com/v5/market/tickers?category=spot&symbol=BTCUSDT` - +--- diff --git a/mengyanote-backend/data/mengyanote/Web3区块链/BTC销毁方法.md b/mengyanote-backend/data/mengyanote/Web3区块链/BTC销毁方法.md new file mode 100644 index 0000000..7c716d8 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/Web3区块链/BTC销毁方法.md @@ -0,0 +1,52 @@ +比特币**没有内置的官方销毁机制**,所有销毁都是通过**协议规则**让某些币变得**永远无法花费**(provably unspendable)。一旦交易被确认进区块,这些币就永久从流通中移除,减少了实际可用的供应量。 + +### 1. 主流销毁方式对比 + +| 方式 | 原理 | 是否真正烧币 | 优点 | 缺点 | 常见用途 | +|-----------------------|-----------------------------------|--------------|-----------------------------------|-----------------------------------|----------| +| **发送到 Burn Address**(最经典) | 把币发到一个**数学上无人拥有私钥**的地址 | 是 | 直观、象征意义强、可长期持有查看 | 会增加UTXO集大小 | 仪式性烧币(如你之前说的107 BTC事件) | +| **OP_RETURN** | 创建一个明确标记为**不可花费**的输出 | 是(输出金额通常为0) | 最干净、省资源、节点不会存储 | 只能附带少量数据(当前~80字节) | 数据铭刻、证明存在、协议销毁 | +| **复杂不可花费脚本** | 使用比特币脚本写出无法满足的条件(如永远False) | 是 | 灵活 | 复杂、占用空间大 | 高级协议 | +| **矿工主动Burn** | 在Coinbase交易中少领取区块奖励 | 是 | 直接减少新发行 | 只有矿工能做 | 极少见 | + +### 2. 最常见的 Burn Address 原理详解 + +**最著名地址:** `1111111111111111111114oLvT2` + +- **核心原因**:它的 **Hash160 = 0000...0000**(20字节全零)。 +- 比特币地址 = 版本前缀 + Hash160 + 校验码。 +- 要花费这个地址的币,需要提供一个公钥,其 Hash160 恰好是全零。 +- 在 secp256k1 椭圆曲线密码学下,这在现实中**不可能**(概率极低,即使量子计算机也极难)。 +- 其他常见 Burn 地址还有: + - `1BitcoinEaterAddressDontSendf59kuE`(吃币地址) + - 各种随机生成的无效地址 + +这些地址**可以接收币,但永远无法转出**。 + +### 3. OP_RETURN 销毁原理 + +这是目前**最推荐、最干净**的销毁方式: + +- 脚本以 `OP_RETURN` 开头。 +- 比特币节点一看到 `OP_RETURN` 就**立即标记为不可花费**,不再存入 UTXO 集。 +- 通常输出金额设为 **0 sat**(防止意外烧币)。 +- 如果你非要附带金额,那部分 BTC 就会被永久烧掉。 +- 主要用于:在链上永久记录数据(如文本、哈希证明、NFT 元数据等),同时实现销毁。 + +### 4. 其他间接「销毁」 + +- **丢失的币**(Lost Coins):私钥丢失、硬件损坏、忘记密码等。目前估计有 **300-400 万 BTC** 永久丢失,这才是比特币实际供应减少的最主要原因(远超主动烧币)。 +- **矿工不领取全部奖励**:极少发生。 +- **Proof of Burn**(某些山寨币机制):把 BTC 烧到特定地址来铸造新币(比特币本身不直接用)。 + +### 5. 实际影响 + +- **总供应**:硬顶 2100 万 BTC。 +- **已挖出**:2026 年约 2000 万+ BTC。 +- **主动烧币量**:相对较少(知名 burn 地址累计几千 BTC 级别)。 +- **真实流通量**:因丢失 + 烧币,远低于已挖出数量,这也是比特币通缩属性的重要来源。 + +**总结一句话**: +比特币销毁的核心就是**把币发送到「协议层面永远无法解锁」的地方**,让它从经济上彻底消失。无论是烧给「全零地址」(交给数学),还是用 OP_RETURN(干净记录),本质都是用比特币的不可篡改性来实现「永久移除」。 + +想深入了解某个具体方式(比如怎么自己安全地用 OP_RETURN 烧一点点做测试),或者看某个著名 burn 地址的实时余额吗?告诉我,我再给你细讲。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/量化投资/polymarket预测市场投资方法.md b/mengyanote-backend/data/mengyanote/Web3区块链/polymarket预测市场投资方法.md similarity index 100% rename from mengyanote-backend/data/mengyanote/量化投资/polymarket预测市场投资方法.md rename to mengyanote-backend/data/mengyanote/Web3区块链/polymarket预测市场投资方法.md diff --git a/mengyanote-backend/data/mengyanote/Web3区块链/web3区块链主流公链总结.md b/mengyanote-backend/data/mengyanote/Web3区块链/web3区块链主流公链总结.md new file mode 100644 index 0000000..fa912f6 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/Web3区块链/web3区块链主流公链总结.md @@ -0,0 +1,31 @@ + +### **顶级主流公链(Tier 1)** + +| 排名 | 公链 | 代币 | 核心特点 | 主要优势领域 | +|------|------|------|----------|-------------| +| 1 | **Ethereum** | ETH | 智能合约鼻祖,PoS + L2生态 | DeFi、NFT、RWA、机构采用、结算层 | +| 2 | **Solana** | SOL | 高性能单体链(高TPS、低费用) | meme币、高频交易、DeFi、消费者应用、DePIN | +| 3 | **BNB Chain** (原BSC) | BNB | EVM兼容,低费用 | 零售交易、GameFi、日常DeFi | +| 4 | **Tron** | TRX | 稳定币支付强链 | USDT流通、跨境支付、新兴市场 | + +### **第二梯队主流公链(Tier 2,影响力显著)** + +- **Avalanche (AVAX)**:子网架构,快速最终性,企业/机构友好。 +- **Polygon**:Ethereum L2聚合器/侧链,扩展性强。 +- **Near Protocol**:用户友好、AI+区块链融合潜力。 +- **Sui / Aptos**(Move语言系):高性能并行执行,新兴资本青睐,成长迅速。 +- **Polkadot (DOT)**:多链互操作(Parachain)。 +- **Cardano (ADA)**:学术驱动,注重可持续性和治理(生态发展相对稳健)。 + +### **其他值得关注的公链** +- **Base**(Coinbase L2):虽是L2,但因Coinbase背书,在Web3采用中非常主流。 +- **Arbitrum / Optimism**:Ethereum主要L2,TVL和活跃度高。 +- **Bitcoin**:严格来说是价值存储公链,但通过Ordinals、Runes等也在Web3生态有一定延伸。 +- **TON**(The Open Network):Telegram生态驱动,用户规模潜力巨大。 + +### **2026年趋势总结** +- **Ethereum** 依然是**去中心化和安全性**的基准,主导机构级采用和RWA。 +- **Solana** 在**性能和用户体验**上领先,尤其适合高频和大众应用。 +- **多链/跨链** 是主流,开发者通常不会只押注一条链。 +- **L2和模块化** 架构(如Rollups、Celestia等DA层)正在分流大量活动,但底层L1公链仍是基础。 +- **稳定币使用** 驱动实际采用:Tron和Solana在支付场景特别强。 diff --git a/mengyanote-backend/data/mengyanote/Web3区块链/币安BTC实时价格监控API.md b/mengyanote-backend/data/mengyanote/Web3区块链/币安BTC实时价格监控API.md new file mode 100644 index 0000000..5c99043 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/Web3区块链/币安BTC实时价格监控API.md @@ -0,0 +1,49 @@ +### 1. 最常用 REST API(当前最新价格) +- **Endpoint**: + ``` + https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT + ``` +- **返回示例**: + ```json + { + "symbol": "BTCUSDT", + "price": "75578.86000000" + } + ``` +**推荐**:简单、轻量、无需 API Key。 +### 2. 24小时行情统计(更全面) +- **Endpoint**: + ``` + https://api.binance.com/api/v3/ticker/24hr?symbol=BTCUSDT + ``` +- **返回包含**:最新价、涨跌幅、最高/最低、成交量等。 +### 3. 实时推送(WebSocket)—— 真正的实时更新 +**推荐用于实时监控**: +- **单个交易对**: + ``` + wss://stream.binance.com:9443/ws/btcusdt@ticker + ``` +- **多个交易对**(推荐): + ``` + wss://stream.binance.com:9443/stream?streams=btcusdt@ticker/ethusdt@ticker + ``` +- **其他常用 Stream**: + - `btcusdt@trade`:逐笔成交 + - `btcusdt@bookTicker`:最佳买卖盘 + - `btcusdt@kline_1m`:1分钟K线 +### 其他实用链接 + +| 类型 | Endpoint | 用途 | +| ------- | --------------------------------------- | --------- | +| 平均价格 | `/api/v3/avgPrice?symbol=BTCUSDT` | 5分钟平均价 | +| 深度 | `/api/v3/depth?symbol=BTCUSDT&limit=10` | 订单簿 | +| 所有交易对价格 | `/api/v3/ticker/price` | 返回所有币对最新价 | + +**注意**: +- 无需 API Key 即可调用以上**公开市场数据**接口 +- 生产环境建议使用 `data-api.binance.vision` 作为备用域名(更稳定) +- 频率限制:REST 接口约 1200 次/分钟 +**快速测试**(直接浏览器打开): +``` +https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT +``` diff --git a/mengyanote-backend/data/mengyanote/临时/dex交易所.md b/mengyanote-backend/data/mengyanote/临时/dex交易所.md new file mode 100644 index 0000000..ad817a9 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/dex交易所.md @@ -0,0 +1,62 @@ +**DEX交易所(Decentralized Exchange)** 是**去中心化交易所**的简称,与传统的中心化交易所(CEX,如Binance、Coinbase)完全不同,它不依赖任何中心化机构或公司来运营。 + +### 1. DEX 是什么? +- **核心特点**:用户直接在区块链上通过智能合约进行交易,**用户始终掌握自己的私钥和资产**(非托管)。 +- 常见DEX例子: + - 以太坊生态:Uniswap、SushiSwap、Curve + - Solana生态:Raydium、Jupiter(聚合器) + - Binance Smart Chain:PancakeSwap + - 其他:dYdX、GMX(衍生品DEX)等 + +### 2. DEX 的运作原理(核心机制) + +DEX 的运作主要依赖以下技术: + +#### **(1) 智能合约(Smart Contract)** +- 所有交易逻辑都写在区块链上的公开智能合约中。 +- 合约会自动执行买卖、流动性提供、费用分配等操作,无法被单方面修改(除非治理投票)。 + +#### **(2) 流动性池(Liquidity Pool)—— 最核心的概念** +传统 CEX 用**订单簿(Order Book)**匹配买卖双方,而大多数 DEX(尤其是 AMM 类型)使用**自动化做市商(Automated Market Maker, AMM)**模型: + +- 用户(流动性提供者 LP)把两种资产按一定比例存入**流动性池**(例如 ETH + USDT)。 +- 交易者直接和**流动性池**交易,而不是和其他用户直接匹配。 +- 价格由**数学公式**自动决定(最经典的是 **x * y = k** 恒定乘积公式)。 + +**举例**: +假设 ETH/USDT 池子里有 100 ETH 和 200,000 USDT(k = 100 × 200000 = 20,000,000)。 + +- 你想用 1 ETH 换 USDT: + - 池子 ETH 变成 101,k 不变 → USDT 数量变为 20,000,000 / 101 ≈ 198,019.8 + - 你得到约 1,980.2 USDT(扣除手续费前) +- 交易量越大,**滑点(Slippage)** 就越大(因为价格会沿曲线移动)。 + +#### **(3) 交易流程(以 Uniswap 为例)** +1. 你连接钱包(MetaMask 等)。 +2. 选择交易对(例如 ETH → USDC)。 +3. 智能合约从你的钱包扣除 ETH,自动从流动性池中把对应数量的 USDC 转给你。 +4. 交易手续费通常 0.3%(不同池子不同),其中一部分给 LP 作为奖励,一部分可能销毁或给协议。 +5. 整个过程在区块链上公开透明、可验证。 + +### 3. DEX vs CEX 对比 + +| 项目 | DEX(去中心化) | CEX(中心化) | +|---------------|-----------------------------|---------------------------| +| 资产保管 | 用户自己(非托管) | 平台保管(托管) | +| KYC | 不需要 | 通常需要 | +| 交易速度 | 较慢(依赖区块链) | 极快 | +| 滑点/流动性 | 大额交易滑点大 | 流动性好,深度高 | +| 安全性 | 智能合约风险、智能合约漏洞 | 平台被黑、跑路风险 | +| 隐私 | 较高 | 较低 | +| 可用资产 | 主要链上代币 | 几乎所有币(含法币) | + +### 4. 其他重要机制 +- **LP(流动性提供者)**:提供流动性赚取交易费,但面临**无常损失(Impermanent Loss)**风险。 +- **闪电贷(Flash Loan)**:很多 DEX 支持借出巨额资金(无需抵押),在一笔交易内借出、用完、归还,若无法归还则交易回滚。 +- **聚合器(Aggregator)**:如 1inch、Jupiter,会同时搜索多个 DEX,帮你找到最佳价格和最低滑点。 +- **衍生品 DEX**:如 dYdX、GMX,使用 U 型资金池或虚拟 AMM,支持杠杆交易、永续合约。 + +### 总结 +DEX 的本质是**把交易所的逻辑搬到区块链上,用数学公式(AMM)和智能合约代替中心化撮合和托管**,实现了**真正意义上的非托管交易**。它的优势是**去信任、透明、抗审查**,但也面临**高Gas费、滑点、无常损失、智能合约风险**等缺点。 + +如果你想了解某个具体 DEX(如 Uniswap V3 的集中流动性)的原理,或者想知道如何安全使用 DEX,我可以再详细讲解。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/临时/golang实现自举历程.md b/mengyanote-backend/data/mengyanote/临时/golang实现自举历程.md new file mode 100644 index 0000000..3fdb120 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/golang实现自举历程.md @@ -0,0 +1,80 @@ + +## 第一阶段:C 编译器启动(Go 1.0 ~ 1.4) + +Go 语言于 2007 年开始开发,最早没有现成的 Go 编译器来编译 Go 代码。因此: + +- **编译器本身用 C 编写**:最初的 Go 编译器(`5c`、`6c`、`8c` 等对应不同架构)是用 C 语言实现的。 +- **运行时(runtime)用 C 和汇编编写**:垃圾回收、协程调度等核心组件初期也是 C 语言实现。 +- 这个阶段用C 编译器(如 GCC 或 Plan 9 C 编译器)来编译 Go 的工具链。 + +--- + +## 第二阶段:用 Go 重写关键组件(Go 1.2 ~ 1.4) + +从 Go 1.0 开始,团队就开始逐步用 Go 语言替换 C 语言实现: + +| 版本 | 主要改动 | +|------|---------| +| **Go 1.0 ~ 1.2** | 将一些命令行工具(如 `go` 命令本身)改为 Go 实现 | +| **Go 1.3** | `gc` 编译器的前端(词法分析、语法分析、类型检查)开始用 Go 重写 | +| **Go 1.4** | 编译器的主体、运行时(runtime)和链接器(linker)大部分已用 Go 实现 | + +**Go 1.4 是最后一个用 C 编译器编译的 Go 版本**。它充当了"自举的垫脚石"。 + +--- + +## 第三阶段:完成自举(Go 1.5,2015年) + +Go 1.5 实现了完全自举,具体过程如下: + +### 步骤 1:准备好编译器源码 +Go 1.5 的编译器源码已经 100% 用 Go 语言编写(包括前端、后端、运行时)。 + +### 步骤 2:用 Go 1.4 编译 Go 1.5 +``` +C 编译器 → 编译 Go 1.4 → 得到 Go 1.4 编译器 +Go 1.4 编译器 → 编译 Go 1.5 源码 → 得到 Go 1.5 编译器 +``` +此时 Go 1.5 编译器是用 Go 语言写的,但它是由 Go 1.4(C 编译产物)编译出来的。 + +### 步骤 3:验证一致性 +``` +Go 1.5 编译器 → 编译 Go 1.5 源码 → 得到另一个 Go 1.5 编译器 +``` +两个 Go 1.5 编译器(Go 1.4 编译的 vs Go 1.5 编译的)逐字节对比,如果完全一致,则证明自举成功。 + +### 步骤 4:弃用 C 工具链 +自举成功后,Go 1.5 的发布包不再依赖任何 C 编译器。后续的 Go 版本只需要前一个 Go 版本即可编译。 + +--- + +## 第四阶段:编译器持续优化(Go 1.5 之后) + +自举完成后,Go 编译器完全基于 Go 实现,带来了后续的独立演进: + +| 版本 | 编译器改进 | +|------|-----------| +| **Go 1.5** | 引入**并发 GC**(之前的 GC 是 C 实现的) | +| **Go 1.7** | 引入 **SSA 后端**(Static Single Assignment),用 Go 重写代码生成优化 | +| **Go 1.10+** | 链接器(linker)逐步用 Go 重写,解决大链接问题 | +| **Go 1.19+** | PGO(Profile-Guided Optimization)等高级优化 | + +--- + +## 总结:自举的核心逻辑 + +``` +C 编译器 + ↓ +编译 Go 1.4(最后一个 C 编译版本) + ↓ +Go 1.4 编译 Go 1.5(Go 写的编译器) + ↓ +Go 1.5 编译 Go 1.5(验证一致性) + ↓ +完全自举,此后 Go 编译 Go +``` + +Go 的自举策略非常务实:**先让语言能用,再逐步替换,最后摆脱对 C 的依赖**。这也体现了 Go 语言的设计哲学——先做简单、可用的事,再渐进优化。 + +> 💡 如今,如果你想从源码构建 Go 编译器,只需要一个**前版本的 Go 二进制包**即可,不需要系统中安装 C 编译器。 diff --git a/mengyanote-backend/data/mengyanote/临时/golang面试八股常识.md b/mengyanote-backend/data/mengyanote/临时/golang面试八股常识.md new file mode 100644 index 0000000..60212cb --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/golang面试八股常识.md @@ -0,0 +1,206 @@ + +1. Slice(切片) +动态数组,比数组更灵活、更常用。 +```go +// 创建方式 +s1 := []int{1, 2, 3} // 字面量 +s2 := make([]int, 5, 10) // 长度5,容量10 +s3 := arr[1:4] // 基于数组创建 + +// 核心:slice 包含三个信息 +// - ptr: 指向底层数组的指针 +// - len: 当前元素个数 +// - cap: 底层数组容量 + +// 自动扩容 +s := []int{1, 2, 3} +s = append(s, 4, 5) // 容量不足时会自动翻倍扩容 +``` +关键点:slice 是引用类型,修改会影响原数组;但 append 可能返回新地址。 + +2. Map(映射) +哈希表实现的无序键值对集合。 +```go +// 创建 +m1 := map[string]int{"a": 1, "b": 2} +m2 := make(map[string]int, 100) // 预设容量 + +// 读写 +m1["c"] = 3 // 添加/修改 +value, ok := m1["a"] // 读取,ok判断是否存在 +delete(m1, "b") // 删除 + +// 遍历(随机顺序) +for key, val := range m1 { + fmt.Println(key, val) +} +``` + +重要:map 非线程安全,并发读写需加锁或用 sync.Map。 + +3. Channel(通道) + +Goroutine 间通信的管道,遵循"不要通过共享内存来通信,而要通过通信来共享内存"的理念。 +```go +// 声明创建 +ch1 := make(chan int) // 无缓冲 +ch2 := make(chan string, 10) // 有缓冲(10容量) + +// 发送接收 +ch1 <- 42 // 发送 +value := <-ch1 // 接收 +value, ok := <-ch1 // 接收并检查通道是否关闭 + +// 单向通道 +func send(ch chan<- int) // 只能发送 +func recv(ch <-chan int) // 只能接收 + +// 常用模式 +// 1. 信号通知 +done := make(chan bool) +go func() { + // do work + done <- true +}() +<-done // 等待完成 + +// 2. 生产者消费者 +// 3. 多个goroutine协作 +``` + +关键:无缓冲通道要求发送和接收同时准备好(同步);有缓冲通道在缓冲满前不阻塞。 + +4. sync(同步包) + +提供并发控制的同步原语。 + +```go +// Mutex: 互斥锁 +var mu sync.Mutex +mu.Lock() +// 临界区 +mu.Unlock() + +// RWMutex: 读写锁(允许多个读、单个写) +var rwmu sync.RWMutex +rwmu.RLock() // 读锁 +// 读取操作 +rwmu.RUnlock() + +// WaitGroup: 等待多个goroutine完成 +var wg sync.WaitGroup +for i := 0; i < 5; i++ { + wg.Add(1) + go func() { + defer wg.Done() + // do work + }() +} +wg.Wait() // 等待所有完成 + +// Once: 保证函数只执行一次 +var once sync.Once +once.Do(func() { /* 初始化 */ }) + +// Cond: 条件变量 +cond := sync.NewCond(&mu) +cond.Wait() // 等待条件 +cond.Signal() // 唤醒一个 +cond.Broadcast() // 唤醒所有 +``` + +5. Context(上下文) + +用于传递请求范围的值、取消信号、截止时间,常用于控制 goroutine 的生命周期。 + +```go +// 创建空Context +ctx := context.Background() +ctx := context.TODO() + +// 带取消的Context +ctx, cancel := context.WithCancel(parentCtx) +defer cancel() // 一定要调用释放资源 + +// 带超时 +ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second) +ctx, cancel := context.WithDeadline(parentCtx, time.Now().Add(5*time.Second)) + +// 带值 +ctx := context.WithValue(parentCtx, key, value) + +// 使用示例:控制goroutine退出 +ctx, cancel := context.WithCancel(context.Background()) +go func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return // 收到取消信号退出 + default: + // 正常业务逻辑 + } + } +}(ctx) + +// 一段时间后取消 +time.AfterFunc(3*time.Second, cancel) + +// 传递值(注意:key应该是自定义类型,避免冲突) +type contextKey string +ctx = context.WithValue(ctx, contextKey("user"), "张三") +``` + +6. 反射(Reflection) + +在运行时动态操作类型和值的能力。 + +```go +import "reflect" + +// 基本操作 +var x float64 = 3.14 +v := reflect.ValueOf(x) // 获取值 +t := reflect.TypeOf(x) // 获取类型 + +fmt.Println(t.Name()) // float64 +fmt.Println(v.Float()) // 3.14 + +// 修改值(需要传指针) +var y float64 = 3.14 +v = reflect.ValueOf(&y) // 传指针 +v.Elem().SetFloat(2.5) // 修改值 + +// 反射结构体 +type User struct { + Name string `json:"name"` + Age int +} + +u := User{"Alice", 30} +t := reflect.TypeOf(u) +for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + fmt.Printf("%s: %s %s\n", + field.Name, field.Type, field.Tag) +} + +// 动态调用方法 +func (u User) Say(msg string) string { + return u.Name + " says: " + msg +} + +v = reflect.ValueOf(u) +method := v.MethodByName("Say") +args := []reflect.Value{reflect.ValueOf("Hello")} +result := method.Call(args) +``` + +反射原则: + +· 反射从接口值到反射对象 +· 反射从反射对象到接口值 +· 要修改反射对象,其值必须可设置(addressable) + +谨慎使用:反射会降低性能、增加代码复杂度,优先考虑类型断言等替代方案。 + +--- diff --git a/mengyanote-backend/data/mengyanote/临时/usdt,usdc超级管理员后门.md b/mengyanote-backend/data/mengyanote/临时/usdt,usdc超级管理员后门.md new file mode 100644 index 0000000..0838304 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/usdt,usdc超级管理员后门.md @@ -0,0 +1,31 @@ +**是的,USDT(Tether)和 USDC(Circle)在智能合约代码里都有超级管理员权限(类似后门)。** + +### 1. **USDT (Tether) 的情况** +- **黑名单(Blacklist)机制**:合约内置 `addBlackList(address)`、`removeBlackList(address)` 等函数,只有 Tether 的管理员(特定地址或多签)能调用。 +- 这个权限可以直接**冻结任意地址**的 USDT,让该地址无法转出或接收 USDT(资金还在钱包里,但动不了)。 +- Tether 经常配合执法部门使用这个功能,已冻结过数十亿美元的 USDT(最近例子包括 2026 年冻结 3.44 亿美元)。 +- 不同链(如 Ethereum、Tron)上的 USDT 合约都有类似设计。 + +### 2. **USDC (Circle) 的情况** +- 同样内置 **Blacklist** 功能,有 `blacklist(address)` 和 `unBlacklist(address)`。 +- 只有 Circle 授权的账户(Blacklister 角色)才能操作。 +- Circle 也会根据法院命令或合规要求冻结地址,最近就有冻结 Zama cUSDC 合约(涉及 1260 万美元)的案例。 +- 合约还有 **Pause** 功能,能全局暂停转账。 + +### 3. **为什么说这是“超级管理员后门”?** +- 这些不是 bug,而是**故意设计**的中心化控制功能(为了 KYC/AML 合规)。 +- 发行方(Tether/Circle)掌握 **mint(铸币)、burn(销毁)、blacklist、pause** 等特权。 +- 合约代码是开源可查的(Etherscan 等),但权限掌握在公司手里,不是去中心化。 + +### 总结对比: + +| 项目 | 是否有超级管理员 | 主要权限 | 实际使用频率 | +|------------|------------------|-------------------|--------------| +| **USDT** | 有 | Blacklist、Mint/Burn | 非常频繁 | +| **USDC** | 有 | Blacklist、Pause | 频繁 | +| **BTC/ETH** | 无 | 无 | - | + +**风险提醒**: +持有 USDT/USDC 就意味着接受发行方的中心化控制,资金可能因合规、法律原因被冻结。如果你追求完全去中心化,建议用去中心化稳定币(如 DAI)或纯加密资产。 + +想查具体合约代码,可以去 Etherscan 查看 USDT(0xdac17f958d2ee523a2206206994597c13d831ec7)或 USDC(0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48)的 Read Contract 部分,里面能看到 blacklist 相关函数。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/临时/web1,web2,web3以及web4特点与区别.md b/mengyanote-backend/data/mengyanote/临时/web1,web2,web3以及web4特点与区别.md new file mode 100644 index 0000000..ba77b32 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/web1,web2,web3以及web4特点与区别.md @@ -0,0 +1,75 @@ + +--- + +## Web1(只读网络,约 1990–2004) + +| 特征 | 说明 | +|------|------| +| **静态内容** | 页面是只读的 HTML,内容由网站所有者发布 | +| **用户角色** | 纯消费者,只能浏览,不能互动 | +| **典型代表** | 早期门户网站(Yahoo!、搜狐、新浪)、个人静态主页 | +| **技术栈** | HTML、CSS、静态服务器、CGI 脚本 | +| **核心模式** | "信息展示"——你只能看,不能写 | + +> 用户是内容的**读者**,不是参与者。 + +--- + +## Web2(读写网络,约 2004–现在) + +| 特征 | 说明 | +|------|------| +| **用户生成内容** | 任何人都可以发布、评论、点赞、分享 | +| **平台为中心** | 数据和服务集中在平台手中(Facebook、Twitter、YouTube、微信) | +| **互动社交** | 社交网络、评论系统、即时通讯、直播 | +| **商业模式** | 平台通过用户数据变现(广告、推荐算法) | +| **技术栈** | AJAX、JavaScript 动态交互、REST API、数据库驱动 | +| **核心模式** | "平台即服务"——你创造内容,平台拥有数据和控制权 | + +> 用户是内容的**创造者**,但平台是**控制者**和**数据拥有者**。 + +--- + +## Web3(读-写-拥有网络,约 2014–现在,正在发展中) + +| 特征 | 说明 | +|------|------| +| **去中心化** | 数据存储在区块链/IPFS 上,不依赖中心服务器 | +| **用户拥有数据** | 通过私钥控制自己的身份、资产和数据 | +| **代币经济** | 使用加密货币/NFT 进行价值交换和激励 | +| **智能合约** | 自动化、不可篡改的协议执行 | +| **DAO** | 去中心化自治组织,社区投票决策 | +| **典型代表** | Ethereum、IPFS、Uniswap、ENS、Arweave | +| **核心模式** | "用户拥有"——你创造的内容和数据**真正属于你** | + +> 用户是**数据的主人**和**网络的参与者/拥有者**。 +> +> ⚠️ 注意:Web3 目前仍处于早期阶段,存在高波动性、监管不确定性和可扩展性问题。 + +--- + +## Web4(智能/共生网络,概念阶段,约 2020s+) + +| 特征 | 说明 | +|------|------| +| **AI 原生** | AI 不是附加功能,而是网络的基础架构层 | +| **人机共生** | AI 主动理解用户意图,自动完成任务,而非被动响应 | +| **自主智能体** | AI 代理代替用户执行复杂操作(订票、谈判、编程) | +| **语义理解** | 机器真正理解内容的含义,而非仅仅匹配关键词 | +| **多模态交互** | 语音、图像、视频、文本无缝融合交互 | +| **万物互联** | 将 AI + IoT + 区块链 + 边缘计算融合在一起 | +| **概念来源** | 欧盟委员会在 Web4 战略中提出(2023),强调"人与 AI 的共生交互" | + +> 用户不是操作者,而是**引导者**——AI 理解你的需求并主动为你服务。 + +--- + +## 对比总结 + +| 维度 | Web1 | Web2 | Web3 | Web4 | +|------|------|------|------|------| +| **角色** | 读者 | 创作者 | 拥有者 | 引导者 | +| **控制权** | 网站所有者 | 平台公司 | 用户自己 | 用户 + AI 协作 | +| **数据** | 静态文件 | 平台数据库 | 区块链/IPFS | 分布式 + AI 语义 | +| **核心** | 信息展示 | 社交互动 | 价值所有权 | 智能代理 | +| **比喻** | 图书馆 | 广场 | 数字主权城邦 | 私人管家 | diff --git a/mengyanote-backend/data/mengyanote/临时/八股/GoFrame框架.md b/mengyanote-backend/data/mengyanote/临时/八股/GoFrame框架.md new file mode 100644 index 0000000..9a6e6f6 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/八股/GoFrame框架.md @@ -0,0 +1,252 @@ +GoFrame(简称GF)完整详细介绍 + +一、框架基础定位 + +GoFrame 是国产企业级、模块化一站式Go开发框架,对标Java SpringBoot、PHP Laravel,主打全组件开箱即用、工程标准化、中文文档完善、高并发,国内互联网大厂广泛落地(腾讯、医联、金融、电商等) 。 + +- 官网:https://goframe.org.cn/ +- 版本:主流 v2(完整重构,泛型、接口化、云原生适配) +- 核心口号:模块化、高性能、工程完备 +- 适用场景:HTTP接口、RPC微服务、定时任务、CLI工具、脚本、分布式后台、高并发业务 + +二、核心设计理念 + +1. 模块化松耦合 +所有组件独立包,可单独引入使用(不用整套框架,只拿ORM/缓存/日志也行);组件基于接口抽象,支持自定义底层替换(Adapter适配器模式) 。 +2. 工程化规范优先 +内置统一项目分层、代码目录、DAO/Model生成、配置规范,解决团队代码风格混乱问题。 +3. 隐式初始化 + 全局便捷调用 +绝大多数组件无需手动new,全局 g.Xxx() 直接使用,降低样板代码。 +4. 全中文生态 +官方文档100%中文,大量国内业务场景示例(MySQL、Redis、微信支付、分布式锁、分库分表)。 +5. 云原生友好 +原生支持Docker、K8s、健康检查、链路追踪、日志采集、Prometheus监控。 + +三、核心优势对比(Gin/Echo vs GoFrame) + +维度 GoFrame Gin +组件完整度 全家桶:ORM、缓存、定时、校验、日志、RPC、消息队列、国际化、swagger 仅HTTP路由,其余需自行集成第三方库 +开发工具链 内置gf CLI脚手架:一键创建项目、生成Model/Controller、热重载、数据库迁移 无官方CLI,工具零散 +ORM能力 内置gdb,支持链式查询、事务、分库分表、软删除、自动时间戳、读写分离 无内置ORM,需搭配gorm/xorm +安全内置 参数校验、XSS过滤、SQL防注入、JWT、限流、跨域中间件 无内置校验/安全组件 +上手成本 类Laravel MVC,PHP/Java开发者零门槛 偏原生Go,需要自行封装基础能力 +性能 基准损耗约5%,满足绝大多数业务 纯路由损耗3%,极致性能略强,但配套缺失 + +四、整体分层架构(三层结构) + +1. 底层基础层(基础工具包,可独立导入) + +框架最底层通用能力,不依赖上层服务: + +-  gcontainer :高性能并发容器(gmap、gtree、gqueue、glist,解决原生map非并发安全缺陷) +-  gcfg :配置管理(yaml/json/toml/环境变量、多配置文件、热更新) +-  glog :分级日志、文件切割、异步日志、日志链路、自定义输出 +-  gvalid :强大参数校验(结构体标签、自定义校验规则、中文错误提示) +-  gstr/gconv :字符串、类型转换工具,自动类型兼容 +-  gtime :时间处理、定时任务(cron标准表达式) +-  gfile :跨平台文件操作 +-  ghttpclient :内置HTTP客户端,支持连接池 +-  gcrypto :加密工具(MD5、AES、RSA、Base64) + +2. 核心业务层(服务核心能力) + +-  ghttp :HTTP服务(路由、中间件、规范路由、WebSocket、静态文件、文件上传) +-  gdb :内置ORM数据库组件(MySQL/PostgreSQL/SQLite/Oracle/SQLServer) +-  gredis :Redis客户端,连接池、分布式锁、缓存封装 +-  grpc :原生GRPC微服务支持 +-  gsession :会话管理(内存/Redis存储) +-  gi18n :国际化多语言 +-  gqueue :异步队列、任务消费 +-  gcache :统一缓存抽象层(内存/Redis双实现) + +3. 应用工程层(项目脚手架、规范、工具) + +- gf CLI命令行工具(项目初始化、代码生成、热运行、数据库迁移) +- 标准MVC/三层架构模板(api/controller/service/model/dao分层) +- 自动Swagger OpenAPI接口文档生成 +- 分布式组件:链路追踪、限流熔断、注册发现 + +五、核心组件详解 + +1. gf CLI 开发工具(框架灵魂) + +一键完成项目全生命周期,类似Laravel Artisan: + +bash + +# 安装工具 +go install github.com/gogf/gf/v2/cmd/gf@latest + +# 初始化标准项目 +gf init demo-app +cd demo-app + +# 热重载运行(修改代码自动重启) +gf run main.go + +# 根据数据库表生成Model、DAO代码 +gf gen model user + +# 生成控制器 +gf gen controller user + +# 生成swagger接口文档 +gf gen swagger +  + +自动生成标准化目录,统一团队代码结构。 + +2. ghttp Web服务(HTTP核心) + +两种路由模式: + +1. 简单路由:手动注册GET/POST +2. 规范路由(推荐):结构体自动绑定请求参数、自动生成swagger,分层清晰 + +go + +// 极简HelloWorld +package main +import ( + "github.com/gogf/gf/v2/frame/g" +) +func main() { + s := g.Server() + s.GET("/hello", func(r *ghttp.Request) { + r.Response.Write("Hello GoFrame") + }) + s.Run() +} +  + +内置能力:跨域、限流、JWT鉴权、请求日志、参数自动绑定、文件上传、WebSocket。 + +3. gdb ORM(最强内置组件) + +不用引入第三方GORM,原生支持: + +- 链式查询、软删除、自动创建/更新时间戳 +- 事务、嵌套事务、读写分离、分库分表 +- 自动Model映射、结构体批量插入 +- SQL日志打印、慢SQL监控 +- 支持原生SQL混合使用 +示例: + +go + +// 查询单条 +user, err := g.DB().Model("user").Where("id", 1).One() +// 更新 +g.DB().Model("user").Where("id",1).Update(g.Map{"name":"test"}) +  + +4. gvalid 参数校验 + +通过结构体标签自动校验,中文报错: + +go + +type Req struct { + Username string `v:"required|length:6,16#用户名必填|长度6-16位"` + Phone string `v:"phone#手机号格式错误"` +} +  + +支持自定义校验规则、批量校验、接口入参自动校验。 + +5. glog 日志 + +分级日志(Debug/Info/Warn/Error/Panic),自动切割文件、异步输出、链路ID自动携带,支持输出到文件/控制台/ELK。 + +6. gredis Redis封装 + +连接池管理、分布式锁、缓存封装、管道批量操作,统一API屏蔽底层细节。 + +7. 定时任务 gtime.Cron + +标准crontab表达式,支持多任务并行、任务超时控制: + +go + +gtime.NewCron().Add("*/1 * * * *", func() { + g.Log().Info("每分钟执行") +}).Start() +  + +六、标准项目目录结构(gf init生成) + +plaintext + +demo-app/ +├── config/ # 配置文件 yaml +├── api/ # 规范路由请求/响应结构体(swagger来源) +├── internal/ +│ ├── controller/ # 控制器,接收http请求 +│ ├── service/ # 业务逻辑层 +│ ├── model/ # 数据模型(数据库表映射) +│ ├── dao/ # 数据库操作层 +│ ├── logic/ # 复杂业务封装 +│ └── middleware/ # 自定义中间件 +├── manifest/ # 部署、docker、k8s配置 +├── hack/ # 脚本、迁移文件 +├── resource/ # 静态资源、模板、i18n语言包 +└── main.go # 程序入口 +  + +严格遵循接口层-控制器-业务层-数据层分层,企业项目标准规范。 + +七、支持的服务类型 + +1. HTTP Restful API(最常用) +2. GRPC 微服务 +3. TCP/UDP 长连接服务 +4. WebSocket 实时通信 +5. CLI命令行工具 +6. 定时任务常驻程序 +7. 消息队列消费服务 + +八、优缺点总结 + +优点 + +1. 一站式全家桶,不用手动整合各类第三方库,开发效率极高 +2. 完整中文文档+活跃国内社区,问题响应快 +3. CLI工具自动化代码生成,减少重复编码 +4. 内置ORM、缓存、校验、日志,企业级能力齐全 +5. 模块化,可单独抽组件当工具库使用,不强制整套框架 +6. MVC架构贴近Laravel/SpringBoot,PHP/Java转Go学习成本极低 +7. 完善安全防护、监控、链路追踪,开箱即用可上生产 + +缺点 + +1. 相比Gin这种极简路由框架,底层有少量性能损耗(绝大多数业务无感知) +2. v1与v2版本不兼容,新项目直接使用v2 +3. 重度封装,底层原理需要一定时间熟悉 + +九、适合人群 & 技术选型场景 + +✅ 推荐使用: + +- 从PHP Laravel、Java SpringBoot转型Go的开发团队 +- 中小型企业后台、管理系统、API服务 +- 需要快速迭代、规范统一的多人协作项目 +- 高并发接口、分布式微服务、定时任务系统 +- 不想自己封装ORM、缓存、日志、校验的开发者 + +❌ 不推荐: + +- 极致追求极致QPS、零框架损耗的超高性能网关(选纯Gin) +- 仅写简单小工具,只需要极简http路由 + +十、和你之前问的set关联补充 + +GF中大量使用 Set 方法做配置/参数赋值: + +go + +// 配置设置 +g.Cfg().Set("server.port", 8080) +// 路由设置中间件 +s.Group("/api").Middleware(mid.Jwt).SetLog(true) +// ORM设置查询条件 +g.DB().Model("user").Set("name", "xxx") diff --git a/mengyanote-backend/data/mengyanote/临时/八股/ReAct和Plan-Execute模式区别.md b/mengyanote-backend/data/mengyanote/临时/八股/ReAct和Plan-Execute模式区别.md new file mode 100644 index 0000000..d59b1b9 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/八股/ReAct和Plan-Execute模式区别.md @@ -0,0 +1,111 @@ +ReAct Agent 与 Plan-Execute(规划执行)工作流完整讲解 + +一、ReAct(Reasoning + Acting)工作流 + +1. 核心定义 + +ReAct 是边思考、边行动、边观察的循环迭代范式,无全局前置完整计划,每一步只基于上一轮结果临时决定下一步操作。 + +2. 标准循环流程(无限循环直到任务完成) + +1. Thought(推理思考):LLM 根据当前上下文、上一步工具返回结果,判断下一步该做什么工具调用 +2. Action(执行动作):调用工具(搜索/数据库/接口/代码执行) +3. Observation(观察反馈):接收工具返回数据,存入上下文 +4. 回到 Thought,重复循环 + +流程简写: Thought → Action → Observation → Thought ...  + +3. 示例(查北京今日气温) + +1. Thought:需要调用天气工具查询北京实时温度 +2. Action:weather_api(city="北京") +3. Observation:26℃,晴 +4. Thought:已有数据,直接整理答案输出,任务结束 + +4. 核心特点 + +- 无前置全局规划,走一步看一步; +- 环境实时变化、未知路径任务天然适配; +- 每轮都要调用LLM做决策,长任务Token消耗持续上涨; +- 容易短视:多步骤长任务易跑偏、重复调用工具、陷入死循环; +- 结构简单,实现成本低,绝大多数轻量Agent默认方案。 + +二、Plan-Execute(规划-执行)工作流 + +1. 核心定义 + +规划与执行完全解耦,分两大独立阶段:先全局一次性生成完整步骤清单,再逐条执行;执行异常时仅局部重规划,不会全盘推翻。 + +2. 完整工作流程 + +阶段1:Plan 全局规划(Planner模块) + +仅输入用户原始需求,不调用任何外部工具,LLM一次性拆解出结构化任务清单(有序步骤/DAG任务图),明确: + +- 每一步目标 +- 所需工具 +- 步骤依赖关系 +- 任务完成校验标准 + +阶段2:Execute 分步执行(Executor模块) + +循环逐条执行计划内步骤,保存每一步结果; + +- 正常:顺序执行,收集结果; +- 异常/计划失效:触发局部Replan,仅更新剩余未执行步骤; +全部执行完成后,汇总所有步骤结果输出最终答案。 + +流程简写: + 用户需求 → Planner生成完整计划 → Executor逐条执行 → 汇总输出(异常局部重规划)  + +3. 示例(写一份手机市场调研报告) + +1. Plan阶段:一次性生成4步完整计划 +① 搜索2026手机市场出货数据 +② 检索主流品牌份额对比 +③ 收集用户购机偏好调研 +④ 整合数据生成完整报告 +2. Execute阶段:依次执行4步,保存每一步搜索结果;若第2步无数据,仅重新规划第2步,不重置全部流程。 + +4. 核心特点 + +- 拥有全局视角,步骤逻辑清晰,不会遗漏关键流程; +- Token集中消耗在规划阶段,执行阶段LLM轻量化调用,整体成本更低; +- 可并行无依赖子任务,提升执行效率; +- 可解释性极强:完整计划可展示、可人工校验、可回滚; +- 不适合完全未知、环境动态剧烈变化的探索类任务。 + +三、两大范式核心区别对比 + +对比维度 ReAct(边想边做) Plan-Execute(先规划后执行) +决策模式 单步即时决策,无全局计划 一次性生成完整全局步骤清单 +模块耦合 规划、执行混合在同一个LLM循环 Planner规划器 / Executor执行器完全解耦 +全局视野 短视,只能看到上一步结果 全程掌握全部任务链路,步骤依赖清晰 +动态调整能力 极强,每一步都能彻底改变后续路线 局部调整,整体框架不变,仅重规划剩余步骤 +Token开销 随步骤线性持续上涨,长任务成本高 规划一次性消耗Token,执行阶段开销极低 +稳定性(长任务) 差,易跑偏、重复工具调用、死循环 优秀,目标不漂移,步骤可校验 +可解释性 弱,需要追溯整条思考链 强,前置计划可直接查看、人工审核 +并发支持 几乎无法并行执行 天然支持无依赖步骤并行执行 +实现复杂度 简单,单循环即可落地 复杂,需要独立规划、执行、重规划逻辑 + +四、适用场景选型 + +✅ 优先选 ReAct + +1. 短链路任务(3~5步以内); +2. 环境动态、路径不可预判(网页点击、游戏交互、实时问答); +3. 轻量工具调用、低延迟需求; +4. 未知探索类任务(爬虫、浏览器自动化)。 + +✅ 优先选 Plan-Execute + +1. 长链路复杂任务(报告、数据分析、代码工程、多文件开发); +2. 步骤有强依赖、需要严格流程管控; +3. 要求可审计、可人工干预、可展示执行流程; +4. 批量任务、支持并行子步骤,控制Token成本; +5. 企业生产级Agent,追求稳定性、减少幻觉。 + +五、极简一句话总结 + +- ReAct:摸着石头过河,走一步决定下一步 +- Plan-Execute:先画完整施工图,再按图纸施工,出问题只改局部图纸 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/临时/八股/Redis底层数据结构.md b/mengyanote-backend/data/mengyanote/临时/八股/Redis底层数据结构.md new file mode 100644 index 0000000..f2f1e23 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/八股/Redis底层数据结构.md @@ -0,0 +1,93 @@ +Redis 底层主要支持以下 **8 种核心数据结构**: + +## 1. SDS (Simple Dynamic String) - 简单动态字符串 +- **用途**:String 类型的底层实现 +- **特点**:预分配空间、O(1) 获取长度、二进制安全(可存任意字节) + +## 2. quicklist - 快速列表 +- **用途**:List 类型的底层实现(Redis 3.2+) +- **特点**:双向链表 + ziplist 的混合体,兼顾插入速度和内存效率 + +## 3. ziplist - 压缩列表 +- **用途**:List(旧版)、Hash、Set、ZSet 在小数据量时的底层实现 +- **特点**:紧凑的连续内存块,省内存但修改效率低 + +## 4. hashtable (dict) - 哈希表 +- **用途**:Hash 类型的底层实现(数据量大时) +- **特点**:两个哈希表渐进式 rehash,O(1) 读写 + +## 5. intset - 整数集合 +- **用途**:Set 类型的底层实现(元素全为整数且数量少时) +- **特点**:有序整数数组,支持升级(int16 → int32 → int64) + +## 6. skiplist - 跳跃表 +- **用途**:Sorted Set (ZSet) 类型的底层实现之一 +- **特点**:多层索引链表,O(logN) 范围查询,和 hashtable 配合使用 + +## 7. listpack - 紧凑列表 +- **用途**:Redis 5.0+ 引入,替代 ziplist +- **特点**:解决了 ziplist 的级联更新问题,更安全高效 + +## 8. robj (redisObject) - 对象封装层 +- **用途**:所有数据类型的统一封装 +- **特点**:包含类型、编码、LRU、引用计数、指向底层数据的指针 + +--- + +## 对应关系速查 + +| Redis 数据类型 | 底层编码(数据结构) | +|---|---| +| **String** | SDS / int(整数) / embstr | +| **List** | quicklist(ziplist/listpack + 双向链表) | +| **Hash** | ziplist/listpack(小) / hashtable(大) | +| **Set** | intset(整数且小) / hashtable(大) | +| **ZSet** | ziplist/listpack(小) / skiplist + hashtable(大) | + +**总结**:Redis 通过 **对象封装层(robj)** + **多种底层编码**,根据数据特征自动选择最优结构,平衡内存和性能。 + +--- + +## 核心底层数据结构 + +### 基础结构 +| 结构 | 说明 | 版本 | +|------|------|------| +| **SDS** | 简单动态字符串,String 底层 | 全版本 | +| **dict / hashtable** | 哈希表,Hash/Set 底层 | 全版本 | +| **skiplist** | 跳跃表,ZSet 范围查询 | 全版本 | +| **intset** | 整数集合,Set 小数据优化 | 全版本 | +| **robj** | redisObject 统一封装层 | 全版本 | + +### 列表结构(演进历史) +| 结构 | 说明 | 版本 | +|------|------|------| +| **ziplist** | 压缩列表(旧版) | 全版本,**7.0 起废弃** | +| **quicklist** | 双向链表+ziplist 混合 | 3.2+ | +| **listpack** | 紧凑列表,ziplist 的替代者 | **5.0 引入,7.0 全面替代 ziplist** | + +> Redis 7.0+:`ziplist` 已完全移除,所有原本用 ziplist 的地方(List/Hash/ZSet/Stream)都改用 **listpack** + +## 各数据类型的底层编码 + +| Redis 类型 | 小数据(省内存) | 大数据(高性能) | +|---|---|---| +| **String** | SDS / embstr / int | SDS | +| **List** | quicklist(listpack 节点) | quicklist(listpack 节点) | +| **Hash** | **listpack** | hashtable | +| **Set** | intset(纯整数) | hashtable | +| **ZSet** | **listpack** | skiplist + hashtable | +| **Stream** | **rax 树 + listpack** | **rax 树 + listpack** | +| **HyperLogLog** | 稀疏编码(Sparse) | 密集编码(Dense) | +| **Bitmap / Bitfield** | 基于 SDS 的位图操作 | 基于 SDS 的位图操作 | +| **GEO** | 基于 ZSet(geohash + skiplist) | 基于 ZSet | + +--- + +## 关键变化总结 + +1. **Redis 5.0**:引入 `listpack` 和 `rax`(用于 Streams) +2. **Redis 7.0**:`ziplist` 彻底退出历史舞台,全面被 `listpack` 替代 +3. **新增数据结构类型**:`Stream`(基于 rax + listpack) + +新版 Redis 的底层已经全面 **listpack 化** diff --git a/mengyanote-backend/data/mengyanote/临时/八股/http状态码.md b/mengyanote-backend/data/mengyanote/临时/八股/http状态码.md new file mode 100644 index 0000000..426521c --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/八股/http状态码.md @@ -0,0 +1,50 @@ +HTTP状态码 文档笔记 + +一、核心考察点 + +面试中考察的不仅是对状态码数字的记忆,更看重对一次HTTP请求从成功到失败各种状态的理解,需结合系统架构(登录认证、缓存机制、限流熔断、网关架构等)来掌握。 + +二、分类体系 + +HTTP状态码共分5大类,首位数字代表问题层级: + +- 1xx:消息通知 +- 2xx:成功 +- 3xx:重定向 +- 4xx:客户端错误 +- 5xx:服务端错误 + +三、各分类详细解析 + +1. 2xx 成功状态码 + +- 200 OK:请求成功,服务器正常返回数据。 +- 201 Created:资源创建成功,如注册用户、创建订单,服务器处理成功并新建资源。 +- 204 No Content:请求成功但无返回内容,如删除操作成功,服务器无需返回数据。 + +2. 3xx 重定向状态码 + +- 301 Moved Permanently:永久重定向,如网站域名永久迁移新地址,后续应访问新地址。 +- 302 Found:临时重定向,资源暂时在别处,未来可能返回原地址。 +- 304 Not Modified:资源未修改,浏览器可直接使用本地缓存,减少网络传输。 + +3. 4xx 客户端错误 + +- 400 Bad Request:请求参数有误,如参数格式错误、缺少必填字段。 +- 401 Unauthorized:未认证,即未登录或登录信息失效。 +- 403 Forbidden:已认证但无权限,如普通用户访问管理员接口。 +核心区别 :401是“没身份”,403是“有身份但没资格”。 +- 404 Not Found:资源不存在,如访问不存在的接口或页面。 +- 405 Method Not Allowed:请求方式错误,如接口要求POST却发了GET请求。 +- 429 Too Many Requests:请求过于频繁,触发限流,如超过“一分钟访问100次”的限制。 + +4. 5xx 服务端错误 + +- 500 Internal Server Error:服务器内部异常,如代码报错、空指针、数据库异常。 +- 502 Bad Gateway:网关错误,常见于Nginx转发请求时后端服务挂了或返回异常。 +- 503 Service Unavailable:服务不可用,如系统维护、服务过载、熔断降级。 +- 504 Gateway Timeout:网关超时,请求已发往后端,但后端长时间无响应。 + +四、高频必记状态码 + +- 200(成功)、301/302(重定向)、304(缓存命中)、400(参数错误)、401(未登录)、403(无权限)、404(资源不存在)、429(触发限流)、500(服务器异常)、502(网关错误)、503(服务不可用)、504(请求超时)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/临时/八股/rag检索增强生成.md b/mengyanote-backend/data/mengyanote/临时/八股/rag检索增强生成.md new file mode 100644 index 0000000..dc313ab --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/八股/rag检索增强生成.md @@ -0,0 +1,160 @@ +RAG 向量检索完整详解 + +一、什么是向量检索 & RAG 里的定位 + +RAG = Retrieval-Augmented Generation,检索增强生成。 +核心逻辑:先检索外部知识库真实资料,再喂给大模型生成答案,解决大模型幻觉、知识过时、私有数据无法读取问题。 +向量检索是 RAG 中「检索模块」最主流实现方案,替代传统关键词检索(BM25)。 + +基础概念 + +1. 文本向量(Embedding) +一段文字通过嵌入模型(Embedding Model)转换成固定长度浮点数组(如 768/1024 维),语义相近的文本,向量在高维空间距离更近。 +例: 北京今天天气  和  今日北京气温  向量距离很小;和  猫咪饲养教程  距离极大。 +2. 向量检索 +输入问题 → 转向量 → 在向量库中计算相似度,召回最相似的 Top-N 文本片段,作为上下文给 LLM。 +3. 传统关键词检索缺陷 +只匹配字面词语,不理解语义: +搜“新能源车续航”,只会命中包含“续航”的句子,找不到“电车里程”相关内容;同义词、转述、引申义完全失效。 +向量检索基于语义匹配,完美解决该问题。 + +二、完整 RAG 向量检索全流程(两大阶段) + +阶段1:离线构建知识库(入库流程) + +1. 文档加载 +读取各类私有数据:PDF、Markdown、Word、数据库、网页、接口文本、日志、代码。 +2. 文本分割(Chunk 分块) +长文档不能直接向量化,必须切分小块: + +- 固定长度切分:按 token/字符分割 +- 语义切分:遇到段落、标题、语义断点切割(效果更好) +- 重叠切片(Overlap):块之间留重叠文本,避免上下文断裂丢失信息 +示例:单块 512 token,重叠 80 token。 + +3. Embedding 向量化 +每一块文本送入嵌入模型,生成多维向量。 +常见模型分类: + +- 开源:bge-m3、all-MiniLM、e5、gte(本地部署,无成本) +- 闭源:OpenAI text-embedding、智谱、通义千问 Embedding API + +4. 向量入库 +文本块、向量、原文元数据(来源、标题、页码)一同存入向量数据库。 + +阶段2:在线问答检索流程(推理流程) + +1. 用户输入问题 +2. Query 向量化:用同一个 Embedding 模型把问题转为向量(必须和入库模型统一) +3. 向量相似度检索 +向量库计算问题向量与库内所有文档向量距离,返回相似度最高 Top-K 片段(K 一般取3~8) +4. 重排(Rerank,可选优化) +初筛召回的多条文档送入重排模型,重新打分排序,过滤无关内容,提升上下文质量 +5. 上下文拼接 +把筛选后的文本片段+用户问题组合成 Prompt +6. LLM 接收 Prompt,基于真实检索资料生成回答 + +三、向量相似度计算方式 + +向量是高维数组,通过距离判断语义相似度: + +1. 余弦相似度 Cosine Similarity(RAG 最常用) +只关注向量方向,不受文本长度影响,长短文本对比表现稳定,几乎所有向量库默认使用。 +2. 欧式距离 L2 Distance +向量空间直线距离,数值越小越相似;长文本向量模长会干扰结果,RAG 很少单独用。 +3. 点积 Dot Product +适合归一化后的向量,计算速度快,常配合余弦使用。 + +四、向量数据库(向量存储引擎)分类 + +1. 专业向量数据库(专用优化,生产首选) + +- Milvus:开源高性能,支持海量向量、分片集群、混合检索,企业RAG主流 +- Qdrant:轻量易部署,API友好,适合中小体量知识库 +- Chroma:极简本地向量库,开发调试、本地Demo专用 +- Pinecone:云托管向量库,无需运维,闭源付费 +- Weaviate:自带图数据库+向量,支持混合检索 + +2. 传统数据库向量扩展(已有业务库复用) + +- PostgreSQL + pgvector:业务本身用PG,少量向量场景低成本方案 +- MySQL 8.0+ vector 插件、Redis Stack:缓存+轻量向量检索 + +3. 内存简易向量库 + +FAISS(Meta开源):CPU/GPU高速向量检索库,无持久化,常作为向量计算底层依赖,配合文件/数据库持久化使用。 + +五、核心关键技术细节 + +4. 分块 Chunk 策略(决定检索效果上限) + +- 块太小:单块信息不足,检索片段残缺,模型缺少完整上下文 +- 块太大:向量语义混杂,一段包含多个无关主题,相似度匹配失真 +通用最优实践:中文单块 300–800 token,重叠 10%~20%。 + +2. 检索召回策略 + +1. 近似检索 ANN(主流) +海量向量(百万/亿级)不可能逐一条计算相似度,ANN 通过索引结构牺牲极小精度换取百倍速度。 +索引类型:HNSW(综合最优,Milvus/Qdrant默认)、IVF_FLAT、FLAT(暴力精确检索,仅少量数据)。 +2. 混合检索(Hybrid Search) +向量语义检索 + BM25关键词检索结果融合,兼顾语义与关键词精准匹配,解决纯向量容易丢失专有名词、ID、代码的问题。 + +3. Rerank 重排优化 + +向量初筛只看向量距离,会存在语义相近但和问题无关的文本。 +重排模型(bge-reranker、cross-encoder)输入「问题+文档块」成对打分,精准筛选真正相关内容,大幅降低幻觉,属于生产级标配优化。 + +4. Metadata 元数据过滤 + +入库时给每块打上标签:文档类型、时间、部门、分类。 +检索时先过滤再算向量相似度: +例:只检索2026年业务文档、仅查询API手册,缩小检索范围,减少噪声。 + +六、向量检索优缺点 + +优势 + +1. 理解语义,同义词、转述、间接相关内容均可召回,远强于关键词搜索 +2. 适配非结构化数据:文档、对话、代码、图片文本、音频转写文本 +3. 天然适配大模型,向量空间语义逻辑和LLM对齐 +4. 支持百万、亿级海量知识库实时检索 + +短板 + +1. 纯向量检索容易丢失精确专有名词(订单号、设备ID、专业术语),必须搭配混合检索 +2. 嵌入模型存在语义偏差,领域专属数据需要微调Embedding提升精度 +3. 高维向量存储占用高,海量数据需要集群扩容 +4. 无法精准匹配数字、代码片段、固定格式文本 + +七、和关键词检索(BM25)对比 + +维度 向量检索 BM25关键词检索 +匹配逻辑 语义相似度 字面词语频率 +同义词支持 天然支持 不支持,需手动维护词库 +长文本理解 优秀 差,容易断章取义 +专有名词/ID 弱 极强 +适用场景 通用知识库、问答、模糊查询 代码、单据、精确词条查询 +最佳方案 混合检索同时启用两者融合得分 单独使用仅精准查找场景 + +八、完整最简技术链路示例 + +私有PDF知识库问答系统: + +1. PDFLoader 读取文件 → 语义分割Chunk +2. bge-m3 生成向量 +3. Milvus 存储向量+原文+元数据 +4. 用户提问 → 向量化 → HNSW索引检索Top5 +5. bge-reranker 重排过滤无关片段 +6. 拼接检索上下文 + 问题构建Prompt +7. LLM 基于检索资料生成回答 + +九、常见落地调优方向 + +1. 更换领域专属Embedding模型(法律/医疗/代码专用向量模型) +2. 调整Chunk大小、重叠长度,优化分割逻辑 +3. 开启混合检索(向量+BM25)融合打分 +4. 增加Rerank重排步骤 +5. 元数据前置过滤缩小检索范围 +6. 调整召回Top-K数量,平衡上下文长度与噪声 +7. 向量库索引参数调优(HNSW层数、邻点数)提升速度/精度平衡 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/临时/八股/前后端登录验证方式总结.md b/mengyanote-backend/data/mengyanote/临时/八股/前后端登录验证方式总结.md new file mode 100644 index 0000000..046c311 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/八股/前后端登录验证方式总结.md @@ -0,0 +1,187 @@ + +## 一、传统 Session-based 认证(Cookie + Session) + +**原理**:用户登录后,服务器创建 Session 并将 Session ID 存入 Cookie 返回给浏览器。后续请求携带 Cookie,服务器通过 Session ID 查找对应的用户信息。 + +**优点**: +- 实现简单,服务器端可控 +- 可以随时撤销 Session(如强制登出) +- 天然支持 CSRF 保护(同源策略) + +**缺点**: +- 服务器需要存储 Session 状态,扩展性差(多服务器需共享 Session) +- 不适合跨域场景 +- 移动端支持较弱 + +**适用场景**:传统 Web 应用、单体架构 + +--- + +## 二、JWT (JSON Web Tokens) + +**原理**:登录成功后,服务器生成一个包含用户信息的 JWT Token 返回给客户端。客户端后续请求携带 Token(通常在 Authorization Header 中),服务器验证签名即可,无需存储状态。 + +**JWT 结构**:`Header.Payload.Signature` + +**优点**: +- **无状态**:服务器不需要存储会话信息,易于水平扩展 +- **跨域支持**:适合前后端分离、微服务架构 +- **自包含**:Token 中包含用户信息,减少数据库查询 + +**缺点**: +- **无法撤销**:Token 在过期前一直有效(需要配合黑名单机制) +- **体积较大**:包含大量用户信息时 Token 会变长 +- **安全性**:如果密钥泄露,攻击者可以伪造 Token + +**适用场景**:前后端分离应用、微服务、API 认证 + +--- + +## 三、OAuth 2.0(授权框架) + +**原理**:第三方应用通过授权服务器获取访问令牌(Access Token),而非直接使用用户密码。典型流程:用户点击"微信登录"→ 跳转到微信授权页 → 用户授权 → 微信返回授权码 → 应用用授权码换取 Token。 + +**核心流程**: +``` +用户 → 第三方应用 → 授权服务器 → 返回 Access Token +``` + +**优点**: +- 标准化的授权协议 +- 支持多种授权模式(授权码、隐式、密码、客户端凭证) +- 适合第三方登录场景 + +**缺点**: +- 实现复杂 +- 需要维护授权服务器 + +**适用场景**:第三方登录(Google、微信、GitHub 等)、API 授权 + +--- + +## 四、OpenID Connect (OIDC) + +**原理**:在 OAuth 2.0 基础上增加了一层**身份认证**。OAuth 2.0 只解决授权,OIDC 解决认证("用户是谁")。 + +**核心概念**: +- **ID Token**:JWT 格式的身份令牌,包含用户基本信息(sub、name、email 等) +- **UserInfo Endpoint**:获取用户详细信息的 API + +**优点**: +- 标准化的身份认证协议 +- 基于 OAuth 2.0,复用成熟生态 +- 适合 SSO(单点登录) + +**适用场景**:企业级应用、SSO、需要标准身份认证的场景 + +--- + +## 五、API Keys + +**原理**:简单的字符串凭证,通常用于服务间通信或第三方 API 调用。 + +**优点**: +- 实现简单 +- 适合机器对机器通信 + +**缺点**: +- 不适合用户认证 +- 一旦泄露,风险较高 + +**适用场景**:第三方 API 调用、内部服务通信 + +--- + +## 六、密码哈希存储(安全存储) + +**原理**:用户密码不能明文存储,需要使用哈希算法加密。 + +**主流算法**: +- **bcrypt**:自适应哈希,抗 GPU 暴力破解 +- **scrypt**:内存硬函数,抗 ASIC 攻击 +- **Argon2**:密码哈希竞赛冠军,抗侧信道攻击 + +**最佳实践**: +```javascript +// 存储密码 +const hashedPassword = await bcrypt.hash(password, 12); + +// 验证密码 +const isValid = await bcrypt.compare(password, hashedPassword); +``` + +--- + +## 七、现代密码less认证 + +### 1. Magic Links(魔法链接) +**原理**:用户输入邮箱 → 服务器发送包含临时 Token 的链接 → 用户点击链接完成登录。 + +**优点**:无需密码,用户体验好 +**缺点**:依赖邮箱,有延迟 + +### 2. WebAuthn / Passkeys(无密码认证) +**原理**:使用生物识别(指纹、面容)或硬件密钥进行认证,基于公私钥对。 + +**优点**: +- 抗钓鱼攻击 +- 无需记忆密码 +- 安全性极高 + +**缺点**:需要设备支持 + +### 3. TOTP(时间一次性密码) +**原理**:基于时间生成 6 位数字验证码(如 Google Authenticator)。 + +**优点**:双因素认证,安全性高 +**缺点**:需要额外步骤 + +--- + +## 八、组合方案(推荐) + +现代应用通常**组合使用**多种方式: + +| 方案 | 适用场景 | 安全性 | 用户体验 | +|------|----------|--------|----------| +| JWT + Refresh Token | 前后端分离应用 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | +| Session + CSRF Token | 传统 Web 应用 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | +| OAuth 2.0 + OIDC | 第三方登录/SSO | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | +| WebAuthn + TOTP | 高安全场景 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | + +### 典型架构示例:JWT + Refresh Token + +``` +登录流程: +1. 用户提交用户名密码 +2. 服务器验证通过,返回: + - Access Token(短期有效,如 15 分钟) + - Refresh Token(长期有效,如 7 天) +3. 客户端使用 Access Token 访问 API +4. Access Token 过期时,使用 Refresh Token 获取新的 Access Token +5. Refresh Token 过期时,需要重新登录 +``` + +--- + +## 九、安全最佳实践 + +1. **HTTPS**:所有认证通信必须使用 HTTPS +2. **Token 存储**:Access Token 存内存,Refresh Token 存 HttpOnly Cookie +3. **密码策略**:强制复杂度、定期更换 +4. **速率限制**:防止暴力破解 +5. **审计日志**:记录登录行为 +6. **多因素认证**:敏感操作启用 MFA + +--- + +## 总结 + +| 技术 | 核心思想 | 适合场景 | +|------|----------|----------| +| Session | 服务器存储状态 | 传统 Web 应用 | +| JWT | 客户端存储状态 | 前后端分离、微服务 | +| OAuth 2.0 | 授权框架 | 第三方登录 | +| OIDC | 身份认证层 | SSO、企业应用 | +| WebAuthn | 公私钥认证 | 无密码、高安全 | + diff --git a/mengyanote-backend/data/mengyanote/临时/八股/栈与堆:概念、区别及内存管理详解.md b/mengyanote-backend/data/mengyanote/临时/八股/栈与堆:概念、区别及内存管理详解.md new file mode 100644 index 0000000..0b75f30 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/八股/栈与堆:概念、区别及内存管理详解.md @@ -0,0 +1,57 @@ + +一、栈(Stack) + +1. 核心概念 + +- 是程序内存中按照固定规则使用的区域,遵循**后进先出(LIFO)**原则,可类比“一摞盘子”,最后放入的盘子最先被取出。 +- 用于存储局部变量、函数调用上下文等,函数调用时遵循栈的规则:若  main  调用  A , A  调用  B ,则  B  最先退出, A  其次,最后回到  main 。 + +2. 栈帧(Stack Frame) + +函数调用时,系统在栈上为其创建的内存空间,保存: + +- 函数参数 +- 局部变量 +- 返回地址 +- 程序运行状态 + +函数执行结束后,栈帧会被自动释放,无需程序员手动管理。 + +3. 优势 + +- 管理简单:系统自动分配和释放,无额外管理成本。 +- 速度快:内存使用规则规整,仅需调整栈顶指针即可完成分配/释放。 + +4. 缺点 + +- 空间有限:若函数调用层级过深(如无终止条件的递归),会导致栈溢出(Stack Overflow)。 + +二、堆(Heap) + +1. 核心概念 + +- 是程序运行时动态分配的内存区域,用于存储对象、大小不确定或需长期存在的数据。 +- 需通过特定方式申请(如 C 语言  malloc 、C++  new 、Java  new )。 + +2. 内存管理 + +- 手动管理语言(如 C/C++):申请堆内存后需手动释放(如  free 、 delete ),否则会导致内存泄漏(无用内存未归还系统,长期运行会使程序变慢甚至崩溃)。 +- 带垃圾回收(GC)的语言(如 Java、Go):GC 会自动回收无引用的堆内存,但如果程序错误保留对象引用,仍会造成内存泄漏。 + +3. 优势 + +- 空间大:可动态申请大容量内存。 +- 使用灵活:适合存储大小不确定、需跨函数生命周期的数据(如读取未知大小的文件、共享对象)。 + +三、栈与堆的核心区别 + +维度 栈 堆 +管理方式 系统自动管理 需手动管理(或依赖 GC) +生命周期 跟随函数,函数结束即销毁 可跨函数生命周期,直到释放/回收 +空间大小 通常较小 通常较大 +分配速度 快(仅调整栈顶指针) 慢(需查找空间、处理内存碎片等) + +四、一句话总结 + +- 栈:像函数的临时工作台,空间小、速度快、自动清理,适合存储局部临时数据。 +- 堆:像程序的公共仓库,空间大、使用灵活,但内存管理更复杂,适合存储对象、大块数据等。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/临时/八股/触发跨域类型.md b/mengyanote-backend/data/mengyanote/临时/八股/触发跨域类型.md new file mode 100644 index 0000000..ffbf549 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/八股/触发跨域类型.md @@ -0,0 +1,13 @@ + +判断是否“同源”取决于以下3个要素,任何一个不同,就算跨域: + +· 协议不同:http:// 请求 https://(或 file:// 本地文件请求网络资源)。 +· 域名不同:www.a.com 请求 www.b.com(或主域相同但子域名不同,如 api.a.com 请求 www.a.com 也算)。 +· 端口不同:localhost:3000 请求 localhost:8080(即使 IP 相同,端口不同也算)。 + +特别容易踩坑的 2 个特例: + +· IP 与域名:http://127.0.0.1 和 http://localhost 虽然指向自己,但在浏览器眼里是不同源,会触发跨域。 +· 路径和参数:? 问号后面的参数、# 锚点,不影响同源判断,只看协议、域名、端口。 + +总结:只要你页面所在的源(地址栏)≠ 接口所在的源,浏览器就会触发跨域拦截 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/临时/删除指定网站浏览数据和缓存方法.md b/mengyanote-backend/data/mengyanote/临时/删除指定网站浏览数据和缓存方法.md new file mode 100644 index 0000000..058d6ec --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/删除指定网站浏览数据和缓存方法.md @@ -0,0 +1,52 @@ + +### 1. Google Chrome / Microsoft Edge(方法几乎相同) + +#### **最推荐方式:开发者工具快速清除(单个网站)** +1. 打开目标网站。 +2. 按 **F12**(或 Ctrl+Shift+I)打开开发者工具。 +3. 切换到 **Application**(应用程序)标签。 +4. 在左侧找到 **Clear storage**(清除存储)。 +5. 点击最下方的 **Clear site data**(清除站点数据)。 +6. 刷新页面即可。 + +**额外技巧**: +- 在 Network(网络)标签勾选 **Disable cache**(禁用缓存),然后刷新页面,只对当前网站有效。 + +#### **通过设置管理(更彻底)** +1. 点击右上角 **⋯** → **设置**。 +2. 左侧选择 **隐私和安全** → **Cookie 和其他网站数据**(或 **第三方 Cookie**)。 +3. 点击 **查看所有网站数据和权限**(或 **查看所有 Cookie 和网站数据**)。 +4. 在搜索框输入网站域名(如 `baidu.com`)。 +5. 找到后点击垃圾桶图标删除。 + +### 2. Mozilla Firefox + +#### **推荐方式:管理数据** +1. 点击右上角菜单 **≡** → **设置**。 +2. 左侧选择 **隐私与安全**。 +3. 在 **Cookie 和网站数据** 部分,点击 **管理数据**。 +4. 在搜索框输入网站域名。 +5. 选中后点击 **删除所选项** 或 **删除全部**。 + +#### **开发者工具方式** +1. 按 **F12** 打开工具。 +2. 切换到 **存储**(Storage)标签。 +3. 展开 Cache Storage 或 Local Storage 等,右键删除对应域名的内容。 + +### 3. Safari(Mac/iPhone) + +#### **Mac 版** +1. 打开 Safari → 菜单栏 **Safari** → **设置**(或偏好设置)。 +2. 切换到 **隐私** 标签。 +3. 点击 **管理网站数据**。 +4. 搜索网站域名,选中后点击 **移除**。 + +#### **清空缓存(全部或开发菜单)** +- 启用开发菜单:**Safari** → **设置** → **高级** → 勾选“在菜单栏中显示‘开发’菜单”。 +- 然后 **开发** → **清空缓存**(Command + Option + E)。 + +### 4. 通用快捷键(全部清除,非单个网站) +- Chrome/Edge:**Ctrl + Shift + Delete** +- Firefox:**Ctrl + Shift + Delete** +- Safari:**Option + Command + E**(清空缓存) + diff --git a/mengyanote-backend/data/mengyanote/临时/哈希算法总结.md b/mengyanote-backend/data/mengyanote/临时/哈希算法总结.md new file mode 100644 index 0000000..02dc707 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/临时/哈希算法总结.md @@ -0,0 +1,53 @@ +## 一、 什么是哈希算法? + +哈希算法的本质是**将任意长度的数据,计算并映射成一段固定长度的结果**(这个结果被称为**哈希值**或**摘要**)。无论是输入一句话、一张图片,还是几个GB的视频,其输出的哈希值长度都是固定不变的。 + +## 二、 哈希算法的三大核心特点 + +1. **相同输入,相同输出**:只要原始内容完全没有变化,无论何时、计算多少次,得到的哈希值都一模一样。 + +2. **雪崩效应(输入微调,输出剧变)**:输入的数据只要改变一点点(例如大小写字母转换),算出来的哈希值就会产生巨大的、完全不同的变化。 + +3. **不可逆性**:通常情况下,无法通过固定长度的哈希值反推出原始的输入数据。 + + +## 三、 哈希算法的三大典型用途 + +### 1. 文件完整性校验 + +- **原理**:利用“输入微调、输出剧变”的特点。 + +- **应用**:从官网下载软件时,官方通常会提供一个 SHA256 值。用户下载后在自己电脑上对文件再算一次哈希,如果两个值一致,说明文件完整且未被篡改;若不一致,说明文件已损坏或被动过手脚。 + + +### 2. 安全密码存储(重点) + +- **核心原则**:系统绝对**不能保存明文密码**。正确做法是保存密码对应的哈希值。用户登录时,系统将输入的密码再次计算哈希并与数据库对比。 + +- **密码防破手段——“加盐(Salting)”**: + + - **为什么加盐**:因为很多用户密码太简单(如 `123456`),黑客可以提前制作常见密码的哈希表(彩虹表)进行反查。 + + - **什么是盐**:一段随机字符串。系统将“密码 + 随机盐”组合后再计算哈希。即使不同用户的原始密码相同,由于“盐”不同,数据库存的哈希值也完全不同,从而大幅增加黑客的批量破解成本。 + +- **算法选择建议**: + + - 文件校验:可用 **SHA256**。 + + - 密码存储:**不推荐**用 MD5(已被破解)和 SHA256(因为SHA256计算太快,方便黑客暴力猜解密码)。**优先推荐 bcrypt、scrypt、Argon2**,这些算法故意设计得计算慢、占内存,能有效防范暴力破解。 + + +### 3. 工程与分布式系统(数据快速查找与防篡改) + +- **哈希表(Hash Map)**:通过哈希函数将键(Key)映射到特定位置,从而实现极快的数据查询。 + +- **区块链(Blockchain)**:每一个区块都包含前一个区块的哈希值。一旦有人篡改前面的数据,后续的哈希值全部会对应不上,整条链就会直接暴露异常。 + + +## 四、 什么是哈希“碰撞”? + +- **定义**:两个**不同的输入**算出了**相同的哈希值**,这就是碰撞。 + +- **现状**:从数学上讲,由于输入无限而输出长度固定,碰撞必然存在。安全的哈希算法不是没有碰撞,而是让人在现实时间内**极难构造出有用的碰撞**。 + +- **淘汰警告**:**MD5 算法**目前已被证明可以被轻易构造出碰撞,因此**不再安全**,无法用于安全场景。目前更推荐使用 **SHA256**、**SHA3** 等算法。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具] MD Editor 一个轻量级markdown编辑器.md b/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具] MD Editor 一个轻量级markdown编辑器.md new file mode 100644 index 0000000..4c9aedc --- /dev/null +++ b/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具] MD Editor 一个轻量级markdown编辑器.md @@ -0,0 +1,67 @@ + +作者:树萌芽 + +--- + +## 项目背景 + +其实起因挺简单的:平时写笔记离不开 Markdown,之前一直用Obsidian,但是Obsidian适合笔记整理,而我只想要个简单的markdown编辑器,发现vscode太重了每次打开需要等一段时间,UI也不是很好看,而typora正版太贵了,网上那些破解看着也不是很好,也不支持Android预览和编辑 + +后来干脆想,不如自己写一个算了。正好也想试试 Tauri 跨平台开发到底怎么样,于是打开 Claude Code,用 vibe coding 的方式边聊边写,慢慢把这个编辑器搭了起来。 + +于是就有了这个项目:**MD Editor**,一个基于 Tauri 2 + React + TypeScript 的桌面端 Markdown 编辑器。 + +GitHub 仓库:https://github.com/shumengya/md-editor + +## 这是个什么样的工具 + +说白了就是一个专注于写 Markdown 的编辑器。打开速度快,界面干净,左边写、右边实时预览,支持深色和浅色主题切换。 + +我自己用下来比较舒服的几点: + +- 分屏编辑,码字和看效果互不耽误 +- GitHub 风格的 Markdown 渲染,代码高亮也够用 +- 支持 `Ctrl+S` 保存、`Ctrl+O` 打开这些常规快捷键 +- 退出前如果还有未保存的内容会弹窗提醒,避免手滑关掉 +- 文件在外面被改动时也会提示要不要重新加载 +- Windows 下可以注册右键菜单,双击 `.md` 文件直接打开 + +目前桌面端是主要场景,不过也顺手配了 Android 构建脚本,后面有兴趣可以往移动端再扩展一下。 + +## 用了什么技术 + +- **Tauri v2**:做桌面端壳子,体积小,比 Electron 轻很多 +- **React 19 + TypeScript**:前端界面和状态管理 +- **Vite 6**:开发构建 +- **CodeMirror 6**:编辑器本体,支持 Markdown 语法高亮 +- **Marked + Highlight.js**:把 Markdown 转成 HTML 并做代码高亮 + +Rust 后端只做了最基础的文件读写和 Windows 右键菜单注册,保持简单。 + +## 怎么跑起来 + +需要 Node.js 和 Rust 环境,然后: + +```bash +# 安装依赖 +npm install + +# 开发运行 +npm run tauri dev + +# 构建桌面安装包 +npm run tauri build +``` + +构建好的安装包会在 `src-tauri/target/release/bundle/` 下面。 + +## 为什么开源 + +做这个工具主要是为了自己用着爽,代码也没什么不能看的,就放到 GitHub 上了。如果你正好也在找类似的轻量编辑器,可以下载试试;如果发现问题或者有想法,欢迎提 Issue。 + +后续可能会继续加一些小功能,比如最近打开的文件列表、导出 PDF、自定义字体大小之类的,慢慢来。 + +--- + +感谢阅读,希望这个小工具对你也有用。 +最后给个小彩蛋,这篇文章也是用这个软件写的(=・ω・=) diff --git a/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具] 萌芽表情包图库 —— 一个纯静态的表情包 API + 图库.md b/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具] 萌芽表情包图库 —— 一个纯静态的表情包 API + 图库.md new file mode 100644 index 0000000..36a2933 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具] 萌芽表情包图库 —— 一个纯静态的表情包 API + 图库.md @@ -0,0 +1,174 @@ + +> 项目地址:[github.com/shumengya/meme-api](https://github.com/shumengya/meme-api) +> 在线体验:[meme.smyhub.com](https://meme.smyhub.com) +> 协议:MIT协议 + +--- + +## 前言 + +平时在群里聊天、写博客、做项目文档的时候,经常需要找表情包。网上搜到的图要么带水印,要么链接失效,要么格式不统一,用起来很不顺手。 + +所以我整理了一个表情包图库,VibeCoding做成纯静态站点部署在 Cloudflare Pages 上。打开网页就能翻、能搜、能一键复制链接,也对外提供 JSON API,方便在任何地方调用。 + +目前一共收录了 **51 个分类、2600 多张** WebP / GIF 表情包,全部经过统一处理(最长边缩放到 250px,动图统一为 GIF),体积和兼容性都控制得比较好。 + +--- + +## 说明 + +图库本身是一个单文件 HTML 页面(`public/index.html`),没有任何前端框架、没有任何外部依赖,打开就是下面这样: + +- 左侧分类侧边栏,支持搜索过滤 +- 手机端自动变成 4 列网格,电脑端最多 12 列 +- 点击任意表情弹出操作面板,可以: + - 复制直链 URL + - 复制 Markdown 格式 + - 复制 HTML 嵌入代码(宽度 96~400px 可选,会记住你的偏好) + - 直接下载原图 + +整个页面加载完之后所有交互都是本地的,不需要后端服务。 + +--- + +## 补充 + +如果你不想打开网页,直接用接口拉数据也可以: + +```bash +curl -sS "https://meme.smyhub.com/memes.json" +``` + +返回结构大概长这样: + +```json +{ + "generatedAt": "2026-05-19T13:01:45.229Z", + "categories": [ + { + "id": "白色小人", + "name": "白色小人", + "items": [ + { "file": "1.webp", "path": "白色小人/1.webp" }, + { "file": "2.webp", "path": "白色小人/2.webp" } + ] + } + ] +} +``` + +拿到清单之后,拼接一下就是直链: + +``` +https://meme.smyhub.com/meme/白色小人/1.webp +``` + +中文路径记得 URL 编码,图库里的「复制链接」按钮已经帮你编好了。 + +接口还做了 CORS,任何网页、博客、脚本、聊天机器人都可以直接跨域调用。 + +--- + +## 引用表情 + +在 Markdown 或 HTML 里直接贴: + +```markdown +![哈哈](https://meme.smyhub.com/meme/%E7%99%BD%E8%89%B2%E5%B0%8F%E4%BA%BA/1.webp) +``` + +```html +哈哈 +``` + +因为托管在 Cloudflare Pages,全球边缘节点都有缓存,国内访问速度也还可以。 + +--- + +## 项目结构 + +整个项目非常轻,没有复杂架构: + +``` +meme-api/ +├── public/ +│ ├── index.html ← 图库前端(单文件,零依赖) +│ ├── meme/ ← 处理后的表情包素材 +│ ├── memes.json ← 自动生成的清单 +│ ├── _headers ← CORS 响应头配置 +│ ├── _redirects ← 旧接口兼容 +│ └── readme/index.html ← API 说明页 +├── scripts/ +│ └── generate-manifest.mjs ← 生成 memes.json + 复制到 dist/ +├── 原图/ ← 原始素材 +├── 转化.py ← Python 一键处理脚本 +└── package.json +``` + +### 纯静态,没有后端 + +所有内容都是静态文件。分类列表、搜索、复制、下载,全部在前端用原生 JS 完成。部署只需要把 `dist/` 丢到任意静态托管就行(Cloudflare Pages、Vercel、GitHub Pages、对象存储都可以)。 + +### 零依赖前端 + +`index.html` 是一个完整的单页面应用,内联了所有 CSS 和 JavaScript,没有引用任何外部 CDN。这意味着: + +- 内网环境、离线环境也能打开 +- 不用担心 CDN 挂掉导致页面崩 +- 审计和安全层面很干净 + +### Python 处理脚本 + +新素材丢进 `原图/<分类>/`,运行: + +```bash +python 转化.py +``` + +会自动完成: + +- 未编号素材自动续号 +- 统一转成 WebP(静态)或 GIF(动图) +- 最长边缩放到 250px +- 多线程并行处理 + +处理完的东西会输出到 `原图-已处理/`,再手动拷进 `public/meme/` 就可以上线。 + +--- + +## 部署方式 + +### 方式一:连接 Git(推荐) + +folk本项目仓库后,在 Cloudflare Pages 创建项目,连接 GitHub 仓库的 `main` 分支: + +- 构建命令:`npm run build` +- 构建输出目录:`dist` + +每次 push 会自动触发部署。 + +### 方式二:CLI 直传 + +```bash +npm install +npm run build +npx wrangler pages deploy dist +``` + +--- + +## 总结 + +这个项目本质上就是一个**整理好的表情包文件夹 + 一个能用的前端 + 一个能读的 JSON 接口**。没有花里胡哨的功能,但刚好解决了"找表情、发链接、统一管理"这几个常见痛点。 + +如果你平时也需要大量表情包,或者想给自己的项目搭一个简单的素材 API,可以试着部署一下这个项目。表情包内容会不定期整理更新。 + +--- + +**相关链接** + +- 🌐 在线图库:[meme.smyhub.com](https://meme.smyhub.com) +- 📦 GitHub 仓库:[github.com/shumengya/meme-api](https://github.com/shumengya/meme-api) +- 📖 API 文档:[meme.smyhub.com/readme/](https://meme.smyhub.com/readme/) diff --git a/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具]RandBG API:一个零成本、可自托管的随机背景图片API.md b/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具]RandBG API:一个零成本、可自托管的随机背景图片API.md new file mode 100644 index 0000000..436dfdd --- /dev/null +++ b/mengyanote-backend/data/mengyanote/博客文章/[萌芽妙妙工具]RandBG API:一个零成本、可自托管的随机背景图片API.md @@ -0,0 +1,98 @@ + +> **开源地址**: [github.com/shumengya/randbg-api](https://github.com/shumengya/randbg-api) +> **开源协议**: [MIT License](https://github.com/shumengya/randbg-api/blob/main/LICENSE) +> **在线体验**: [randbg.smyhub.com](https://randbg.smyhub.com) + +--- + +## 前言 + +平时写博客、做落地页,总需要随机背景图。用别人的服务怕挂、怕限速;自己搭又嫌重。我想要一个**够轻、够快、够便宜**的方案——最好不用维护服务器,直接部署就能跑。 + +Cloudflare Workers 的 Free Tier 每月 10 万次请求,对个人项目完全够用。问题是:图片放哪儿? + +直接把图片塞进 Worker 脚本?不行,Worker 有 4 MiB 体积限制,几十张图直接撑爆。 + +所以我把架构拆成两层:Worker 只跑 API 逻辑,图片和前端页面全部走 **Workers Static Assets**。 + +--- + +## 项目架构 + +``` +┌─────────────┐ ┌──────────────────┐ ┌──────────────┐ +│ 用户请求 │────▶│ Cloudflare Worker│────▶│ Static Assets│ +│ │ │ /api/random │ │ WebP 图片 │ +└─────────────┘ └──────────────────┘ └──────────────┘ +``` + +**Worker 端**:不到 200 行 JS,只做三件事——读 `manifest.json`、识别设备、302 或 JSON 响应。 + +**静态端**:`public/` 目录下放 `index.html`、`manifest.json`、编号 WebP 图片。`wrangler deploy` 一次把前后端一起发布。 + +这样做的好处很直接: +- Worker 脚本极小,冷启动几乎无感 +- 图片走 Cloudflare CDN,全球缓存 +- 不涉及数据库,无状态,不存在宕机 + +--- + +## 核心功能 + +### 设备识别 + +根据 `User-Agent` 和 `Sec-CH-UA-Mobile` 自动判断移动端/桌面端,返回对应方向的图片。你也可以手动指定: + +```bash +curl https://randbg.smyhub.com/api/random?mode=mobile +``` + +### 响应格式 + +默认 `302 Redirect` 直接跳转到图片地址,浏览器里一行就能用: + +```html + +``` + +加上 `?format=json` 返回元数据,方便前端自己控制加载逻辑: + +```json +{ + "variant": "desktop", + "folder": "desketop-image", + "filename": "7.webp", + "url": "https://randbg.smyhub.com/desketop-image/7.webp", + "count": 19 +} +``` + +### 构建流程 + +写了个 `build.py`,功能单一但够用: + +1. 扫描 `mobile-image/` 和 `desketop-image/` 目录 +2. 用 Pillow 把原图转为编号 WebP(`1.webp`、`2.webp`...) +3. 输出到 `public/` 并生成 `manifest.json` +4. 如果已有 WebP 且没有原图,自动保留,不会误删 + +```bash +python3 build.py +npm run deploy +``` + +--- + +## 部署 + +整个部署流程是: + +1. 把原图扔进 `mobile-image/` 和 `desketop-image/` +2. `python3 build.py` 转 WebP +3. `npm run deploy` 推到 Cloudflare + +从改图到上线,本地测试用 `npm run dev`,本地 8787 端口就能跑。没有 Docker,没有数据库,没有环境变量要填。 + +--- + +如果你也需要一个零成本、不用维护的随机背景服务,可以直接 Fork 用。代码量很小,改起来不费劲。 diff --git a/mengyanote-backend/data/mengyanote/实习求职/场景题,智力题/1000瓶酒,有一瓶是毒药,多少只老鼠可以查出来?.md b/mengyanote-backend/data/mengyanote/实习求职/场景题,智力题/1000瓶酒,有一瓶是毒药,多少只老鼠可以查出来?.md new file mode 100644 index 0000000..e61ddd9 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/场景题,智力题/1000瓶酒,有一瓶是毒药,多少只老鼠可以查出来?.md @@ -0,0 +1,25 @@ +## 答案:**10 只老鼠** +--- +### 原理:二进制编码 +每只老鼠只有两种状态:**死 (1) 或 活 (0)** +- 10 只老鼠可以表示 2^10 = 1024 种组合 +- 1024 > 1000,刚好够用 +--- + +### 操作方法 +1. 给 1000 瓶酒编号:1, 2, 3, ..., 1000 +2. 将编号转为 **10 位二进制** +3. 第 `i` 只老鼠喝掉所有**第 i 位为 1** 的酒 + +| 酒编号 | 二进制 (10位) | 哪些老鼠喝 | +|--------|---------------|-----------| +| 1 | 0000000001 | 老鼠1 | +| 2 | 0000000010 | 老鼠2 | +| 3 | 0000000011 | 老鼠1,2 | +| ... | ... | ... | +| 1000 | 1111101000 | 老鼠1,2,3,4,5,8,9,10 | + +--- +### 最后一步 +观察哪些老鼠死亡,把**死亡老鼠对应位设为 1**,得到的二进制数就是毒酒编号。 +**例子:** 老鼠 1、3、7 死了 → `0001000101` → 第 69 号酒是毒药 diff --git a/mengyanote-backend/data/mengyanote/实习求职/树萌芽の简历/Golang后端开发.md b/mengyanote-backend/data/mengyanote/实习求职/树萌芽の简历/Golang后端开发.md new file mode 100644 index 0000000..1b3a8c6 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/树萌芽の简历/Golang后端开发.md @@ -0,0 +1,53 @@ +# 个人简历 +icon:user  唐伟 / 男 / 2005.10.25 | icon:phone 15228246485 | icon:email [smyhub@qq.com](smyhub@qq.com) +icon:network  smyhub.com| icon:github [github.com/shumengya](https://github.com/shumengya) +## icon:user 教育背景 +::: start +- **西南石油大学 - 双一流本科 - 网络工程** +::: +**2024-09-01 至 2028-07-01** +::: end + +## icon:technology 专业技能 +- **Go 后端开发基础:** 熟悉 Go 语言基础,熟练使用 Gin 开发 RESTful API,了解 JWT/OAuth2 认证、Goroutine、Channel 并发编程及 GMP 调度模型,具备 GC、内存管理基础认知和常见性能优化意识。 +- **Redis 缓存与应用:** 熟悉 Redis 常用数据结构、缓存设计、分布式锁、持久化机制及主从/哨兵基础,了解缓存穿透、击穿、雪崩等常见问题及应对方案。 +- **消息队列与分布式基础:** 熟悉 RabbitMQ 消息队列,了解异步解耦、削峰填谷等典型场景;对分布式事务、分库分表等基础概念有一定简单认识 +- **MySQL数据库设计与优化:** 熟悉 MySQL 数据库设计、SQL 语句优化、索引优化、联表查询及存储过程;对 MongoDB、SQLite等其他数据库有一定了解和简单实践 +- **DevOps 与容器化部署:** 熟悉使用 Git、Nginx、Docker容器化技术,熟悉Github Action构建流程;具备独立完成 Linux(Debian/Ubuntu)服务器部署、监控与日常运维能力 +- **云计算与边缘部署:** 熟悉使用阿里云、腾讯云云计算平台,同时具备 Vercel、CloudFlare、EdgeOne 等ServerLess边缘计算平台的快速部署与优化能力 +- **前后端协作能力**:了解 React、Vue 等主流前端框架,能使用Vibe Coding进行前端页面搭建,样式美化与基础交互开发,掌握前后端分离架构设计与开发,可配合前端完成完整业务闭环 +- **AI 大模型辅助开发:** 深入掌握 MCP、Skills 及大模型 Agent 开发,熟练使用 Codex、Claude Code、OpenCode 等 AI Agent 工具,以及 Cursor、Trae、GitHub Copilot 等AI 编程工具,大幅提升开发效率 + +## icon:project 项目经历 +- **萌芽小店 - 轻量级商城系统 | 2026.01 - 2026.03** +- **技术栈**:Go(Gin, GORM), MySQL, Redis, Docker, Nginx, React + +- **背景与目标**:独立开发前后端分离商城系统,实现商品展示、下单、自动/手动发货、客服等完整业务闭环,并保障高并发下的数据一致性。后端采用 Handler + Storage + GORM 分层架构,对接自建 SproutGate 第三方网关登录;引入 Redis Cache-Aside 缓存商品列表与站点统计,SET NX 实现多实例浏览去重;通过限购策略与订单状态机约束降低并发超卖风险;使用 Docker + Nginx 完成容器化部署,管理后台集成 API/MySQL/Redis 基础信息面板便于排查。 + +- **项目成果**:系统已成功上线稳定运行,支持 PWA 离线缓存与站点维护模式。 + +- **上线地址**:https://store.shumengya.top **|** **开源地址**:https://github.com/shumengya/mengyastore + +- **SproutClaw - 服务器运维 Agent 助手 | 2026.03 - 2026.05** +- **技术栈**:ReAct, Skills, MCP, Agent RPC, , Prompt Engineering, Harness Engineering, RAG + +- **背景与目标**:基于 Pi-Agent 框架开发个人 AI 运维助手,降低 CLI Agent 使用门槛,提升 DevOps 场景下自动化操作的可靠性。为 CLI Agent 开发浏览器端 WebUI,支持流式输出、历史会话、Markdown 渲染与响应式布局;定制 SSH、GitHub、Gitea、部署等 Skills,设计多服务器操作 Prompt 规范;开发聚合搜索 MCP 工具扩展 Agent 网络搜索能力;构建基于 Markdown 的轻量 RAG 知识库并封装为 Skills,减少 Agent 幻觉。 + +- **项目成果**:助手已部署上线,可完成代码修改、服务部署、远程服务器操作等自动化任务。 + +- **上线地址**:https://sproutclaw.shumengya.top **|** **开源地址**:https://github.com/shumengya/sproutclaw + + + + + +## icon:trophy 荣誉奖项 +- 2025年全国大学生数字媒体科技作品及创意竞赛移动应用开发赛道国家二等奖 ,CET-4 + + + +## 自我评价 +热爱编程开发,熟悉 Go 语言、Redis、MySQL 及容器化部署,能独立完成从设计到上线的全链路开发。项目经验覆盖商城、运维助手等场景,注重实际生产与可运维性。具备前端协作与 AI 辅助开发能力,善于学习,乐于团队合作。 + + + diff --git a/mengyanote-backend/data/mengyanote/实习求职/简历/Java后端开发.md b/mengyanote-backend/data/mengyanote/实习求职/树萌芽の简历/Java后端开发.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/简历/Java后端开发.md rename to mengyanote-backend/data/mengyanote/实习求职/树萌芽の简历/Java后端开发.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/简历/运维工程师.md b/mengyanote-backend/data/mengyanote/实习求职/树萌芽の简历/运维工程师.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/简历/运维工程师.md rename to mengyanote-backend/data/mengyanote/实习求职/树萌芽の简历/运维工程师.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/简历/Golang后端开发.md b/mengyanote-backend/data/mengyanote/实习求职/简历/Golang后端开发.md deleted file mode 100644 index 4af090d..0000000 --- a/mengyanote-backend/data/mengyanote/实习求职/简历/Golang后端开发.md +++ /dev/null @@ -1,40 +0,0 @@ -# 后端开发工程师 -icon:user 男 / 2005.09.23 | icon:phone 15228246485 | icon:email [m](xxxxxxxx@163.com)ail@smyhub.com -icon:network  smyhub.com| icon:github [github.com/](https://github.com/acmenlei)shumengya | icon:tag  note.shumengya.top -## icon:user 教育背景 -::: start -- **西南石油大学 - 双一流本科 - 网络工程** -::: -**2024-09-01 至 2028-07-01** -::: end - -## icon:technology 专业技能 -- **Go 语言核心并发与性能调优:** 熟悉 Goroutine 调度、Channel 并发模型及 GMP 模型,了解内存逃逸分析与 GC 调优。 -- **Web 服务与微服务开发:** 熟悉使用 Gin、GoFrame 开发高性能 RESTful 服务,掌握中间件与路由分组;熟悉 gRPC + Protocol Buffers 构建微服务 -- **缓存认证与分布式中间件:** 熟悉掌握 Redis(缓存、分布式锁)、JWT/OAuth2 认证、消息队列(RabbitMQ、Kafka)等核心组件,具备高并发场景下的稳定性保障能力 -- **数据库设计与优化:** 熟悉 MySQL 数据库设计、SQL 语句优化、索引优化、联表查询及存储过程;对 MongoDB、PostgreSQL、SQL Server 等 NoSQL 与关系型数据库有一定了解和简单实践 -- **DevOps 与容器化部署:** 熟悉使用 Git、Docker、Nginx 及 LXC 容器化技术,熟悉 Maven、Gradle 构建流程;具备独立完成 Linux(Debian/Ubuntu)服务器部署、监控与运维能力 -- **云计算与边缘部署:** 熟悉使用阿里云、腾讯云云计算平台,同时具备 Vercel、CloudFlare、EdgeOne 等ServerLess边缘计算平台的快速部署与优化能力 -- **前后端协作能力**:熟悉 React、Vue 等主流前端框架,能使用Vibe Coding进行前端页面搭建,样式美化与基础交互开发,掌握前后端分离架构设计与开发,可配合前端完成完整业务闭环 -- **AI 大模型辅助开发:** 深入掌握 MCP、Skills 及大模型 Agent 开发,熟练使用 Codex、Claude Code、OpenCode 等 AI Agent 工具,以及 Cursor、Trae、GitHub Copilot 等AI 编程工具,大幅提升开发效率 - -## icon:project 项目经历 -- **项目名称**:萌芽小店-网关登录的轻量级商城系统 **|** 2026.1 - 2026.03 -- **技术栈**:Go(Gin,GORM),MySQL,RabbitMQ / Redis,Docker,Nginx,Vue,PWA -- **描述**:前后端分离的轻量级商城系统,支持商品展示与下单、自动/手动发货、邮件通知、收藏夹、客服消息、维护模式与 PWA 离线缓存;后台覆盖商品/订单/对话与 SMTP、站点运维。后端分层(Handler + Storage + GORM),对接第三方网关登录与多环境配置、容器化部署;公开接口、用户态与管理员令牌分层鉴权,限购与订单状态约束降低并发超卖风险。引入 Redis:商品列表与站点统计走 Cache-Aside、管理端写后失效,浏览去重用 SET NX 适配多实例,缓存不可用时降级直查数据库;管理后台提供 API/MySQL/Redis 连接与基础信息面板,便于排查。前端路由守卫与接口封装统一调用方式。 -- **项目地址**:https://store.smyhub.com **|** **开源地址**:https://github.com/shumengya/mengyastore -- **项目名称**:SproutClaw-服务器运维Agent助手 **|** 2026.3 - 2026.05 -- **技术栈**:ReAct,Skills,Agent RPC,TypeScript,MCP,Prompt Engineering,RAG -- **描述**:基于Pi-Mono Agent框架定制开发个人 AI 运维开发助手,覆盖代码修改、服务部署、远程服务器操作、会话管理和工具调用等场景。重点开发WebUI界面,为CLI Agent增加浏览器端互动界面,支持流式输出、历史会话、Markdown 渲染、响应式设计;同时定制中文启动界面、状态栏、TPS 统计、多服务器操作Prompt规范和 SSH/GitHub/Gitea/部署等技能能力,开发CloudFlare聚合搜索MCP给予AI网络搜索,和构建部署了一个轻量版基于MarkDown笔记的知识库系统,并暴露成Skills给Agent调用,提升Agent在真实 DevOps 场景中的实用性和自动化效率。 -- **项目地址**:https://sproutclaw.smyhub.com **|** **开源地址**:https://github.com/shumengya/sproutclaw - -## icon:trophy 荣誉奖项 -- 2025年全国大学生数字媒体科技作品及创意竞赛移动应用开发赛道国家二等奖 ,CET-4 - - - -## 自我评价 -热爱编程开发,熟悉 Go 语言、Redis、MySQL 及容器化部署,能独立完成从设计到上线的全链路开发。项目经验覆盖商城、运维助手等场景,注重实际生产与可运维性。具备前端协作与 AI 辅助开发能力,善于学习,乐于团队合作。 - - - diff --git a/mengyanote-backend/data/mengyanote/实习求职/通用面试八股/Agent面试八股.md b/mengyanote-backend/data/mengyanote/实习求职/通用面试八股/Agent面试八股.md index 3d52d70..bb8e91f 100644 --- a/mengyanote-backend/data/mengyanote/实习求职/通用面试八股/Agent面试八股.md +++ b/mengyanote-backend/data/mengyanote/实习求职/通用面试八股/Agent面试八股.md @@ -1,14 +1,14 @@ -## 1.**如何定义一个Agent?它通常由哪些核心组件构成?** +# Agent + +## 1.如何定义一个Agent?它通常由哪些核心组件构成? ​ **Agent** = LLM(大脑) + Memory(记忆) + Tools(手) + Planning(决策) + Goal(目标) -## 2.说下**ReAct**框架。它是如何将思维链和行动结合起来,以完成复杂任务的? 了解**Plan-and-Solve吗 ,Reflection**吗 - -![4-1.CPkLktBw](./assets/f71df44372340fabe6e46ef3790036efe8551e6f.png) +## 2.说下ReAct框架。它是如何将思维链和行动结合起来,以完成复杂任务的?了解 Plan-and-Solve、Reflection 吗? ​ **React**核心在于智能体 不断重复这个Thought-Action-observation循环,将新的结果追加的历史记录中去,形成一个不断增长的上下文,直到在Thought中认为已达到了正确答案 @@ -28,9 +28,46 @@ 3)GOT思维图 -![image-20260321102005219](./assets/f1a62c5b977d44495879c58e12feb208ee3352f8.png) -3.1 深入剖析ReAct框架的局限性,并在此基础上,详细解释Plan-Then-Act、ReAct + 轻规划以及Tree/Graph Planning(如ToT、LATS)这三种范式的核心区别、适用场景和各自的优缺点。【待回答】 -3.2 请阐述“思维链”(Chain-of-Thought, CoT)与“规划”(Planning)的本质区别。为什么说CoT仅仅是“将推理过程写出来”,而Planning是生成一个“可执行的任务表”?请用具体例子说明。【待回答】 +### 3.1 深入剖析ReAct框架的局限性,并在此基础上,详细解释Plan-Then-Act、ReAct + 轻规划以及Tree/Graph Planning(如ToT、LATS)这三种范式的核心区别、适用场景和各自的优缺点。 + +**ReAct的局限性:** + +1)缺乏全局规划:每步只基于当前观察做局部决策,容易陷入局部最优 +2)上下文膨胀:Thought-Action-Observation 不断追加,长任务下 token 线性增长,易撞上下文窗口 +3)错误累积:早期一步走错,后续难以回头,无回溯机制 +4)无并行能力:单线串行,不能同时探索多条路径 +5)强依赖模型自身推理能力,小模型效果差 + +**三种范式对比:** + +| 范式 | 核心思路 | 适用场景 | 优点 | 缺点 | +| :--- | :--- | :--- | :--- | :--- | +| **Plan-Then-Act** | 先一次性生成完整计划,再按计划执行 | 步骤明确、环境稳定的任务(编译流程、固定流水线) | 全局视角、执行高效、计划可缓存 | 刚性强,环境变化时计划失效,缺乏应变 | +| **ReAct + 轻规划** | ReAct 循环前先给出粗粒度 todo,执行时仍可动态调整 | 中等复杂度、需要方向感又需灵活性的任务 | 兼顾方向感与应变,实现简单 | 计划粒度难把握,仍受上下文膨胀困扰 | +| **Tree/Graph Planning**(ToT、LATS) | 把推理组织成树/图,每节点是一个状态,可并行探索多分支,用评估函数打分并支持回溯。LATS 进一步结合 MCTS 蒙特卡洛树搜索 + ReAct,多次 rollout 采样、价值函数评估、反向传播更新 | 需要探索、有多个候选解、可回溯的复杂任务(代码生成、解谜、推理题) | 能逃出局部最优、支持回溯、可并行 | 计算成本高(多次调用 LLM)、实现复杂、对评估函数敏感 | + +### 3.2 请阐述“思维链”(Chain-of-Thought, CoT)与“规划”(Planning)的本质区别。为什么说CoT仅仅是“将推理过程写出来”,而Planning是生成一个“可执行的任务表”?请用具体例子说明。 + +**本质区别:** + +- **CoT**:在生成最终答案前,把推理过程逐步“说”出来。本质是**单次生成过程中的内部展开**,输出的是推理文本,不产生外部副作用,不可执行、不可校验。 +- **Planning**:生成一个**结构化、可执行的任务列表/动作序列**,每一步对应具体工具调用或子任务,可被调度器逐项执行、监控、重试、回滚。 + +**具体例子(“小明有3个苹果,吃了1个,又买了2个,还剩几个?”):** + +- **CoT 输出**:“小明原来 3 个,吃了 1 个剩 2 个,又买了 2 个,所以 3-1+2=4 个。” → 只是文字推理过程 +- **Planning 输出**: + - `[step1: get_inventory(user=小明) → 3]` + - `[step2: consume(user=小明, item=苹果, n=1) → 2]` + - `[step3: purchase(user=小明, item=苹果, n=2) → 4]` + - 每步是可执行动作,有真实副作用和返回值 + +**关键差异:** + +1)输出形态:CoT 是文本,Planning 是结构化动作序列 +2)是否落地:CoT 纯推理,Planning 可被引擎执行 +3)可观测性:Planning 每步有输入输出和状态,可监控/重试/回滚 +4)适应性:CoT 一次生成不可变,Planning 可动态调整 ## 4.**Memory**是 Agent 的一个关键模块,如何为 Agent 设计长短时记忆?可以借助哪些外部工具或技术? @@ -42,6 +79,25 @@ ## 5.Tool Use是扩展 Agent 能力的有效途径。请解释 LLM 是如何学会调用外部 API 或工具的?(可以从 Function Calling 的角度解释) +**Function Calling 的核心流程:** + +1)**工具注册**:开发者用 JSON Schema 描述每个工具的 `name`、`description`、`parameters`,随请求一起发给 LLM +2)**模型决策**:LLM 根据用户问题和工具描述,判断是否需要调用工具、调用哪个、参数怎么填 +3)**结构化输出**:LLM 不直接生成自然语言答案,而是返回一个结构化的 function call 对象(含工具名 + 参数) +4)**执行与回填**:业务层解析该对象,真正调用对应 API,把返回结果作为新消息回填给 LLM +5)**二次生成**:LLM 基于工具结果生成最终回答 + +**学会调用工具的两条路径:** + +- **监督微调(SFT)**:用大量 `(指令, 工具调用轨迹)` 样本训练,让模型学会何时调、调什么、参数怎么填。GPT-4、Claude 等支持 function calling 的模型都经过专门微调 +- **提示工程**:对未专门训练的模型,通过 prompt 描述工具 + few-shot 示例,让模型按格式输出,再用正则/解析器提取 + +**关键工程点:** + +- 工具描述质量直接决定调用准确率(description 要写清用途、参数语义、边界) +- 多工具组合:让模型在一个回合内调用多个工具,或链式调用 +- 错误处理:工具返回错误时,把错误信息回填,让模型自行调整参数重试 + ## 6.请比较一下两个流行的 Agent 开发框架,如 LangChain 和 LlamaIndex。它们的核心应用场景有何不同? **Langchain** 应用编排 @@ -89,6 +145,16 @@ ## 11.当一个 Agent 需要在真实或模拟环境中(如机器人、游戏)执行任务时,它与纯粹基于软件工具的 Agent 有什么本质区别? +1)**动作空间**:软件工具是离散的 API 调用,可枚举、可参数化;真实环境是连续的物理动作(移动、抓取),状态空间近乎无限 +2)**反馈延迟**:软件工具即时返回;物理动作反馈慢(秒级甚至更长),且不完整(传感器噪声、遮挡) +3)**可逆性**:软件工具调用通常可重试/回滚;物理动作往往不可逆(打碎的杯子无法复原),试错成本高 +4)**安全约束**:真实环境必须考虑人身安全、设备损坏、环境破坏,需硬约束和兜底;软件环境出错最多丢数据 +5)**状态观测**:软件工具状态完整可见;真实环境部分可观测,需传感器融合、状态估计 +6)**控制频率**:软件 Agent 可低频决策(秒级);机器人需毫秒级实时控制回路 +7)**训练方式**:软件 Agent 主要靠 LLM + 提示/微调;具身 Agent 常需 RL + 仿真环境(Isaac Sim、MuJoCo)训练感知与控制策略 + +**共同点**:都遵循“感知-决策-行动-观察”循环,都可用 Planning + Memory + Tool 架构。 + ## 12.你用过哪些Agent框架?选型是如何选的?你最终场景的评价指标是什么? @@ -138,9 +204,7 @@ Agent:={ -# ***RAG*** - -![RAG.drawio](./assets/04adfee036645335006b33a5650f92838fc19952.png) +# RAG ## 1.请解释 RAG 的工作原理。与直接对 LLM 进行微调相比,RAG 主要解决了什么问题?有哪些优势? @@ -151,12 +215,18 @@ RAG在大语言模型前先访问数据库(向量数据库或者知识图谱 ## 2.RAG 怎么解决 LLM 上下文窗口有限的问题? +1)**检索 Top-K**:只取最相关的 K 个片段(K=3~10)拼进 prompt,而不是塞整篇文档 +2)**分块策略**:把知识库切成小块,按需加载必要片段 +3)**多级索引**:父子块策略,小块检索、大块返回,控制送入 LLM 的总量 +4)**摘要压缩**:长文档先做摘要入库,查询时先拿摘要再按需展开细节 +5)**上下文管理**:滑动窗口 + 摘要保留对话历史,为新问题腾出窗口 +6)**分段生成**:长答案分段生成,前段结果作为下段上下文,逐步累积 +7)**长上下文模型兜底**:用 128K/1M 窗口模型(Gemini、Claude 等),但仍靠检索控制成本和精度 + ## 3.Function Call,MCP了解么 -![image31](./assets/image31.png) - 图中4是function call ``` @@ -290,10 +360,44 @@ MCP插件 ## 8.除了基础的向量检索,你还知道哪些可以提升 RAG 检索质量的技术? +1)**混合检索(Hybrid Search)**:向量检索 + BM25 关键词检索融合,兼顾语义与字面匹配,用 RRF 或加权融合 +2)**重排序(Rerank)**:用 Cross-encoder 模型(bge-reranker、Cohere Rerank)对初筛 Top-K 重新打分,精度远高于 Bi-encoder +3)**查询改写/扩展**: + - Query Rewriting:让 LLM 把口语化问题改写成更利于检索的形式 + - HyDE:先让 LLM 生成假设答案,用假设答案的向量去检索 + - Multi-Query:生成多个语义等价的问题并行检索,结果合并去重 + - Step-back Prompting:先问更抽象的上位问题,再细化 +4)**元数据过滤**:给 chunk 打标签(时间、来源、作者、章节),检索前先按元数据硬过滤 +5)**语义路由**:先对问题分类,路由到对应知识库子集或不同检索策略 +6)**知识图谱增强**:用 KG 做实体链接和关系遍历,补充结构化知识 +7)**多级索引**:父子块、摘要索引 +8)**上下文压缩**:对检索到的长片段做抽取式压缩,只保留与问题相关的句子 +9)**反馈学习**:记录用户点击/采纳的答案,用于微调 embedding 或 reranker + ## 9.如何全面地评估一个 RAG 系统的性能?请分别从检索和生成两个阶段提出评估指标 +**检索阶段:** + +- **Recall@K**:相关文档是否出现在 Top-K 里 +- **Precision@K**:Top-K 里相关文档的比例 +- **MRR**(平均倒数排名):第一个相关文档排名倒数的均值 +- **NDCG@K**:考虑排序位置的归一化增益 +- **Hit Rate@K**:至少有一个相关文档被检索到的比例 +- **Context Recall**:检索到的上下文覆盖标准答案所需信息的比例 + +**生成阶段:** + +- **Faithfulness(忠实度)**:答案是否只基于检索到的上下文,不编造(用 LLM-as-judge 或 NLI 模型判断) +- **Answer Relevancy**:答案与问题的相关性 +- **Context Precision**:检索到的上下文中有多少真正对答案有用 +- **Context Relevancy**:上下文与问题的相关度 +- **端到端**:EM(Exact Match)、F1、BLEU、ROUGE、人工评分 +- **幻觉率**:答案中无上下文支撑的陈述占比 + +**主流框架**:RAGAS、TruLens、LlamaIndex Evaluation + ## 10.在什么场景下,你会选择使用图数据库或知识图谱来增强或替代传统的向量数据库检索? @@ -312,8 +416,6 @@ MCP插件 ​ 2)向量数据库则依相似性度量算法(如余弦相似度)实现模糊匹配。 -​ ![img](./assets/blog-upload-1743529636933-426667190.png) - **从应用场景来看** ​ 知识图谱适用于"**推理性**”场景 @@ -332,10 +434,30 @@ MCP插件 ## 11.传统的 RAG 流程是“先检索后生成”,你是否了解一些更复杂的 RAG 范式,比如在生成过程中进行多次检索或自适应检索? +1)**迭代检索(Iterative Retrieval)**:每生成一段就基于新信息再检索一次,逐步细化 +2)**自适应检索(Self-RAG)**:让 LLM 自己判断是否需要检索、检索结果是否够用、要不要重检索,用反射 token 控制检索时机与粒度 +3)**Flare(Forward-Looking Active Retrieval)**:生成过程中检测到不确定性(低概率 token)时主动触发检索 +4)**多跳检索(Multi-hop)**:把复杂问题分解为子问题,每跳检索一次,结果作为下一跳的输入 +5)**Agentic RAG**:把 RAG 封装成 Agent 工具,由 Agent 决定何时检索、检索什么、如何综合 +6)**GraphRAG**:基于知识图谱的关系遍历检索,适合多跳推理 + ## 12.RAG 系统在实际部署中可能面临哪些挑战? +1)**数据质量**:脏数据、重复数据、过时数据污染知识库,需持续治理 +2)**检索质量**:embedding 选型、切块策略、召回率不足 +3)**实时性**:知识库更新后如何快速重建索引;流式数据接入 +4)**规模与性能**:百万级文档的向量检索延迟、向量库水平扩展、内存压力 +5)**成本**:embedding 调用、LLM 推理、rerank 模型都是成本项 +6)**上下文窗口**:长问题 + 多片段易超窗口,需压缩和取舍 +7)**评估困难**:缺乏标注数据,端到端评估指标不统一 +8)**幻觉控制**:模型可能忽略上下文编造答案 +9)**多租户与权限**:不同用户能看到的知识范围不同,需做检索级权限控制 +10)**安全与合规**:敏感数据泄露、prompt 注入、越权访问 +11)**版本与回滚**:知识库版本管理、效果退化时快速回滚 +12)**冷启动**:初期没有用户反馈数据,难做个性化优化 + ## 13.什么是RAG中的"幻觉"问题?如何预防? @@ -348,6 +470,24 @@ MCP插件 ​ 在RAG架构中,由于检索信息与模型生成之间的错配,导致模型仍然产生幻觉的现象。这是幻觉在RAG场景下的具体表现。 +​ **预防措施:** + +​ 1)检索侧:提高召回率确保关键信息不缺失(混合检索、rerank、多查询扩展) + +​ 2)上下文侧:明确标注“以下是参考资料”,只允许基于资料作答;去除无关片段减少干扰 + +​ 3)Prompt 侧:强约束指令“如果资料中没有答案,请直接说不知道,不要编造” + +​ 4)生成侧:低温度(0~0.3)、限制 max_tokens、禁止自由发挥 + +​ 5)后置校验:用 NLI 模型或 LLM-as-judge 检查答案每句话是否被上下文支持(Faithfulness 评分),不通过触发重生成或拒绝输出 + +​ 6)引用强制:要求答案标注来源片段编号,无来源的陈述视为幻觉 + +​ 7)自我反思:Self-RAG 式地让模型自检答案是否有依据 + +​ 8)持续监控:线上记录幻觉 case,回流到评估和优化流程 + ## 14.GraphRAG与传统RAG有什么区别? 1. GraphRAG与传统RAG的核心区别在于:**传统RAG将知识视为孤立的文本片段,而GraphRAG将知识构建成相互关联的实体网络,实现关系感知的检索与推理**。 @@ -395,13 +535,41 @@ MCP插件 ## 15.如果RAG系统返回0个检索结果,你会如何排查问题? +**排查链路(从上游到下游):** + +1)**查询侧**:用户 query 是否为空/异常字符;是否超 embedding 窗口;语言是否与库一致 +2)**Embedding**:query embedding 是否成功;维度是否与库一致;模型版本是否变更(版本不一致会导致向量空间错位) +3)**索引**:向量库是否为空;索引是否构建完成;是否被误删 +4)**检索参数**:top_k 是否设为 0;相似度阈值是否过高;元数据过滤条件是否过严(把所有结果过滤掉了) +5)**距离度量**:cosine/L2 是否与构建时一致,用错度量会得到反直觉结果 +6)**内容侧**:知识库内容是否与 query 语义完全不相关(领域漂移);chunk 是否切得过碎导致语义丢失 +7)**系统侧**:向量库服务是否健康;网络/超时;连接池耗尽 +8)**兜底**:0 结果时返回友好提示、改用关键词检索、或让 LLM 直接作答并标注“未找到依据” + ## 16.了解Transformer 吗? -11transformer.drawio +Transformer 是 2017 年《Attention is All You Need》提出的纯注意力架构,是现代大模型的基石。 + +**核心组件:** + +1)**Encoder-Decoder 结构**:Encoder 编码输入序列为上下文表示,Decoder 自回归生成输出 +2)**Self-Attention**:每个位置与序列所有位置计算注意力权重,公式 `Q·K^T/√d → softmax → ·V`,捕捉长距离依赖 +3)**Multi-Head Attention**:多组 QKV 并行注意力,不同头关注不同子空间,拼接后线性投影 +4)**Position Encoding**:正弦/可学习位置编码注入顺序信息(Self-Attention 本身无序) +5)**Feed-Forward Network**:每个位置过两层 MLP + 激活(ReLU/GELU) +6)**残差连接 + LayerNorm**:稳定深层训练 + +**变体:** + +- **Encoder-only(BERT)**:理解类任务,分类、检索 +- **Decoder-only(GPT 系列、LLaMA)**:生成类任务,当前主流大模型 +- **Encoder-Decoder(T5、BART)**:翻译、摘要 + +**优势**:并行计算(vs RNN 串行)、长程依赖、可扩展性(堆叠层数和参数) ## 17.准确率和召回率的区别? @@ -412,15 +580,67 @@ MCP插件 - 提升精准率:重排序、阈值过滤、语义去重 - 目标:召回率:> 90 % , 精准率 > 85 % -## **18.什么是“混合检索”(Hybrid Search)?请解释为什么在工业级RAG系统中,纯向量检索往往不够用,需要结合关键词检索(如BM25)。请给出一个具体的业务场景,说明混合检索的必要性。** +## 18.什么是“混合检索”(Hybrid Search)?请解释为什么在工业级RAG系统中,纯向量检索往往不够用,需要结合关键词检索(如BM25)。请给出一个具体的业务场景,说明混合检索的必要性。 + +**纯向量检索的不足:** + +1)对专有名词、ID、代码、型号等字面精确匹配弱(向量关注语义,“SKU-12345”会被语义相近但不同的商品淹没) +2)对低频词、罕见术语表达力差(embedding 训练时见得少) +3)对短查询(1-2 个词)语义信号弱 +4)对数字、日期、精确值不敏感 + +**BM25 等关键词检索的优势:** + +1)基于词频和逆文档频率,对稀有词匹配精准 +2)字面精确匹配强,适合专有名词、代码、ID +3)可解释、可调参、轻量 + +**混合检索做法:** + +1)并行:向量检索拿 Top-K1,BM25 拿 Top-K2 +2)融合:RRF(Reciprocal Rank Fusion,按排名倒数加权)或加权分数融合 +3)Rerank:融合后再用 Cross-encoder 精排 + +**业务场景示例:** + +- **电商客服**:“iPhone 15 Pro Max 256G 价格”——纯向量会返回一堆 iPhone 相关 FAQ,BM25 能精确锁定“15 Pro Max 256G”这个型号;混合后既有型号精确匹配,又能召回“价格/报价/多少钱”等语义变体 +- **法律检索**:条文编号、法条序号必须字面匹配,条文含义需要语义检索 +- **代码问答**:函数名、类名、错误码需精确匹配,代码意图需语义检索 ## 19.在处理一个需要多步工具调用的复杂任务(例如“调研三篇关于RAG+RL的论文并输出中文总结”)时,如何设计一个鲁棒的规划机制来应对中间步骤的失败(如某个API调用超时或返回数据格式错误)?请描述具体的重试、回滚或重规划策略。 +**重试策略:** + +1)**指数退避重试**:对超时/限流类瞬时错误,按 2^n 间隔重试,设最大次数(3~5 次) +2)**区分错误类型**:瞬时错误(超时、429)重试;永久错误(404、参数错误)不重试,直接进入重规划 +3)**参数修正重试**:把错误信息回填给 LLM,让它修正参数后重试 +4)**降级替代**:主工具失败时切换备用工具(某 API 挂了,换另一个等价 API) + +**回滚策略:** + +1)**幂等设计**:每个工具调用带唯一 request_id,重试不会产生重复副作用 +2)**状态检查点**:每步成功后保存 checkpoint,失败时回退到上一个成功点 +3)**补偿事务**:对已产生副作用的失败步骤,执行补偿动作(如已创建的资源删除) + +**重规划策略:** + +1)**局部重规划**:只替换失败步骤,保留前后计划 +2)**全局重规划**:把失败信息和已完成结果反馈给 LLM,重新生成剩余计划 +3)**反思驱动**:Reflection 机制,失败后先分析原因再重规划 +4)**分支探索**:ToT/LATS 式并行尝试多个备选方案,失败分支剪枝 + +**工程实现:** + +- LangGraph 的状态机 + 条件边天然支持重试和回滚节点 +- 设全局超时和预算(最多 N 步、最多 M token),超过强制结束 +- 每步结构化日志,便于事后复盘和 trace +- 兜底:所有重试/重规划都失败时,返回已完成的部分结果 + 明确说明未完成项 -# ***调优*** + +# 调优 ## 1.如何保障调用模型API的健壮性和并发性? @@ -437,15 +657,45 @@ MCP插件 添加超时控制、重试机制与基础降级策略,必要时引入熔断器与监控大 -## 3.在Agent推理过程中,经常会出现“推理断层”或“结果与目标偏离”的问题。请结合具体技术或你的实践经验,说明如何通过提示工程、记忆机制或架构设计来缓解或解决这一问题。【待回答】 +## 3.在Agent推理过程中,经常会出现“推理断层”或“结果与目标偏离”的问题。请结合具体技术或你的实践经验,说明如何通过提示工程、记忆机制或架构设计来缓解或解决这一问题。 + +**1)提示工程:** + +- 任务分解:用 Plan-then-Act,先列 todo 再逐步执行,每步对照 todo 检查 +- 显式目标复述:每 K 步让 Agent 复述一次原始目标和当前进度 +- 结构化输出:强制 JSON Schema 输出(当前步骤、目标、状态、下一步),减少自由发挥 +- 反思提示:每步后加“这一步是否偏离目标?是否需要调整?” + +**2)记忆机制:** + +- 工作记忆持久化:把中间状态写入外部存储(Redis/DB),而非只靠上下文 +- 长期记忆检索:从历史相似任务的经验库里检索参考方案 +- 上下文压缩:定期摘要历史,保留关键决策点,丢弃冗余观察 + +**3)架构设计:** + +- 双层架构:Planner(慢思考,负责规划)+ Executor(快思考,负责执行),Planner 定期校验 +- 状态机/LangGraph:用图结构约束执行路径,避免 Agent 乱跑 +- Critic/Reviewer Agent:独立 Agent 审查每步输出,不通过则回退 +- 限制循环轮次和 token 预算,强制收敛 +- Self-Reflection:失败或偏离时触发反思循环,修正后再继续 -## 4.当历史对话记录非常长时(远超模型上下文窗口),你有哪些策略来优化记忆的查询效率并保证关键信息不丢失?请比较“滑动窗口”、“总结压缩”、“向量检索”等不同方案的优劣。【待回答】 +## 4.当历史对话记录非常长时(远超模型上下文窗口),你有哪些策略来优化记忆的查询效率并保证关键信息不丢失?请比较“滑动窗口”、“总结压缩”、“向量检索”等不同方案的优劣。 -- 滑动窗口:Redis维护短期记忆(近5论对话历史),适配长流程 -- 记忆压缩:设定阈值,超过阈值后调用 阈值前的对话,保留摘要但丢失细节 -- 分层记忆: … +- **滑动窗口**:Redis 维护短期记忆(近5轮对话历史),适配长流程。优点:简单、查询快;缺点:早期信息全丢 +- **总结压缩**:设定阈值,超过阈值后对前段对话用 LLM 摘要,保留要点丢弃细节。优点:省 token;缺点:摘要有损、可能丢关键细节,摘要本身有调用成本 +- **向量检索**:把所有历史对话向量化入库,每轮用当前问题检索相关片段拼回上下文。优点:信息保留全、可跨会话;缺点:检索质量依赖 embedding,可能召回噪音,有延迟 +- **分层记忆(推荐)**: + - L1 工作记忆:最近 N 轮,纯上下文 + - L2 会话摘要:当前会话的阶段性摘要 + - L3 长期向量记忆:跨会话的历史片段,按需检索 + - L4 知识库/用户画像:沉淀的稳定事实(用户偏好、关键决策) + + 每层按重要度和时效分层,查询时分层聚合 +- **实体记忆**:抽取对话中的实体(人、事、物)单独存储,用 KG 维护关系,针对性回答实体相关问题 +- **记忆衰减**:按时间或访问频率衰减,老记忆权重降低,避免噪音堆积 -# ***Skills*** +**选型建议**:短任务用滑动窗口;长会话用摘要 + 向量检索;跨会话个性化用分层记忆 + 实体记忆。 diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅27双非本一腾讯IEG游戏安全后台实习面经.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅27双非本一腾讯IEG游戏安全后台实习面经.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅27双非本一腾讯IEG游戏安全后台实习面经.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅27双非本一腾讯IEG游戏安全后台实习面经.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅4.13字节一面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅4.13字节一面.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅4.13字节一面.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅4.13字节一面.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅Go后端开发-字节一面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅Go后端开发-字节一面.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅Go后端开发-字节一面.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅Go后端开发-字节一面.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节-后端开发面经.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节-后端开发面经.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节-后端开发面经.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节-后端开发面经.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节Agent中台一面凉经.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节Agent中台一面凉经.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节Agent中台一面凉经.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节Agent中台一面凉经.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节一面 4.15.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节一面 4.15.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节一面 4.15.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节一面 4.15.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节一面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节一面.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节一面.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节一面.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节后端2面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节后端2面.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节后端2面.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节后端2面.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节后端一面-65min八股拷打全复盘.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节后端一面-65min八股拷打全复盘.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节后端一面-65min八股拷打全复盘.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节后端一面-65min八股拷打全复盘.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节后端二面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节后端二面.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节后端二面.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节后端二面.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节后端实习三面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节后端实习三面.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅字节后端实习三面.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅字节后端实习三面.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅某佬面试经历.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅某佬面试经历.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅某佬面试经历.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅某佬面试经历.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅某字节一面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅某字节一面.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/✅某字节一面.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端开发/字节/✅某字节一面.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/字节后端开发一面面经.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节/字节后端开发一面面经.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Golang后端/字节后端开发一面面经.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节/字节后端开发一面面经.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节国际支付二面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节/字节国际支付二面.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节国际支付二面.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节/字节国际支付二面.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节跳动TikTok后端开发日常实习一面面经.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节/字节跳动TikTok后端开发日常实习一面面经.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节跳动TikTok后端开发日常实习一面面经.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节/字节跳动TikTok后端开发日常实习一面面经.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/某字节二面面经.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节/某字节二面面经.md similarity index 100% rename from mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/某字节二面面经.md rename to mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/字节/某字节二面面经.md diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/腾讯/腾讯IEG后台开发日常实习二面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/腾讯/腾讯IEG后台开发日常实习二面.md new file mode 100644 index 0000000..eb863ad --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/腾讯/腾讯IEG后台开发日常实习二面.md @@ -0,0 +1,29 @@ +自我介绍 +1.Redis 线程模型 +2.先更新数据库,再删除缓存,删除失败消息队列补充重试+ttl 兜底的策略,会出现数据不一致吗? +3.还有其他的保证数据一致性的方案吗? +4.乐观锁解决超卖,具体的 SQL 语句是怎么写的? +5.concurrentHashMap 怎么保证线程安全的?链表转红黑树的阈值为什么是 8? +6.synchronized 锁升级的过程 +7.什么情况下偏向锁会比轻量级锁的性能差? +8.介绍一下 ThreadLocal +9.JVM 是如何完成垃圾对象标记的?标记垃圾对象的时候,用户线程可以正常工作吗? +10.了解 zgc 垃圾回收器吗? +11.MySQL 的 InnoDB 存储引擎有哪些隔离级别 +12.幻读问题是哪种隔离级别来解决的? +13.比如 1-10 这个范围的 10 个数据,搜 6-9 之间的范围查询,会加哪些锁?加临键锁锁住 [6,9)了,9-10 之间能插入数据吗? +14.Spring AOP 及其实现原理 +15.创建 Bean 对象的时候,AOP 是如何工作的? +16.Bean 对象的生命周期 +17.Function calling 实现预约到店的具体方式 +18.智能客服用的什么大模型?是本地部署的吗? +19.ai 其他地方有什么探索吗?你平时都怎么用 ai +20.一个游戏,假如有 1000w 玩家,如何设计一个匹配算法,具体使用什么数据结构和算法? +21.如果玩家登录不上,你会从哪些方面去 debug,排查问题 +22.CPU 或内存突然飙升,怎么去排查? +23.MySQL 中事务回滚用到的什么日志? +24.一个游戏,玩家的数据更新过程中,MySQL 的几个日志是如何工作的? + +手撕:本地 ide +反转链表 +k 个一组反转链表 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/腾讯/腾讯ieg后端日常实习一二三面面经.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/腾讯/腾讯ieg后端日常实习一二三面面经.md new file mode 100644 index 0000000..f547641 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/面试经历/Java后端开发/腾讯/腾讯ieg后端日常实习一二三面面经.md @@ -0,0 +1,34 @@ +一面(25min)一度以为kpi面...... +1.讲讲数据结构 +2.数组与链表区别,如何选择 +3.hashmap,hashtable实现原理 +4.hashmap哈希冲突高,遍历久,如何处理 +5.哈希表的其他设计方案,除了使用数组+链表 +6.除了链表/红黑树,还有没有其他方法解决哈希冲突 +7.http,https是什么,以及区别,适用场景 +8.tcp,udp区别,适用场景 +9.http,https,tcp,udp的联系 +10.mysql索引,作用,原理,数据结构,为什么用B+树,还有哪些数据结构 +算法:最长递增子序列 +----------------------------------- +二面(50min) +智力题: +1.无限水,两个容器,容量为5L、3L,如何获得4L水 +2.100本书,两个人轮流拿,每次拿1-5本,你先拿,如何保证拿到最后一本 +算法: +两道,有一道是二叉树广度优先的递归版本,另一个不记得了...... +项目: +如何保证不超卖与一人一单,lua脚本是怎么实现的,redis如何调用lua脚本 +场景题: +mysql中一个表数据量大,查询慢,如何优化 +介绍一下大模型,AI,transformer +其他的有点忘了,太久远... +----------------------------------- +三面(50min) +无手撕,全程项目,问到的都是一些项目中的细节: +1.有哪些数据表,哪些字段,如何设计的 +2.项目整体架构,整体流程 +3.有哪些难点,如何解决的 +4.缓存击穿中的数据具体是什么数据,为什么是这些数据,有多大 +5.lua脚本中的命令是怎么保证不被其他命令打断,底层原理(不会) +6.线程池底层原理,如果让你来设计线程池,如何设计 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/树萌芽の面试经历/2026.6.18深势科技Golang后端一面.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/树萌芽の面试经历/2026.6.18深势科技Golang后端一面.md new file mode 100644 index 0000000..0e23f37 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/面试经历/树萌芽の面试经历/2026.6.18深势科技Golang后端一面.md @@ -0,0 +1,18 @@ +### 1.自我介绍 +面试官你好,我是来自西南石油大学计算机系网络工程大二的同学,在校期间主要学习Golang和python相关技术栈,课余时间做过许多东西,比如什么博客,短链,个人主页等等这些,我个人也有一些域名和服务器包括云服务器和本地服务器,所以也上线实际部署过我的一些项目,日常也在学习和使用AI相关的辅助开发工具像是什么cursor,codex和claudecode,好的以上就是我的自我介绍,谢谢面试官 +### 2.Redis的zset顶层数据结构是由什么构成 +Redis的zset数据结构是由压缩列表和跳表构成的,这个是有数据量来决定的,如果数据量比较量比较小,如有序集合的元素个数小于128个,元素大小小于64字节,那么就使用压缩列表,反之则使用跳表,注意的是Redis 7之后压缩列表数据结构已被遗弃,新版本使用listpack +### 3.MySQL的innodb相关 +MySQL使用innodb作为默认储存方式的原因如下, +事务支持:innodb支持事务,包括ACID(原子性,一致性,隔离性,持久性),而myisam不支持事务; +并发性能:innodb最小执行单元是行级锁,而myisam最小是表级锁执行操作时会阻塞整张表; +崩溃恢复:innodb支持从redo持久化日志读取回朔操作,可以在MySQL崩溃重启时恢复数据操作 +MySQL的innodb和myisam的区别: +事务 +索引 +锁粒度 +count的效率 +### 4.消息队列 +rocketmq,kafka,rabbitmq 这块再看看 +### 总结 +基础太差了,接下来给我狠狠地看八股!!! diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/树萌芽の面试经历/2026.6.20豆包模拟面试-1.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/树萌芽の面试经历/2026.6.20豆包模拟面试-1.md new file mode 100644 index 0000000..fab2921 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/面试经历/树萌芽の面试经历/2026.6.20豆包模拟面试-1.md @@ -0,0 +1,35 @@ +1.自我介绍 + +2.你提到做了些小规模网站,能详细说说其中一个项目里你用了啥技术 + +3.你再完整说说项目背景、你在项目里担任的角色,以及这些技术具体在项目里是咋应用的 + +4.详细说说你在保障高并发下的数据一致性这块是用了啥策略不,就像简历里提到的缓存和并发控制方面的操作。 + +5.在缓存与一致性策略这块,你用了 Cache - Aside 策略,那当数据更新时,你是先更新缓存还是先更新数据库,怎么保证缓存和数据库数据的一致性呢? + +6.另外在并发控制与订单状态机这块,你提到用限购策略与订单状态机约束降低并发超卖风险,能具体讲讲这个订单状态机是怎么设计和工作的不? + +7.你用的先更新数据库再更新缓存的策略在大部分场景下能保证一致性,但在高并发下还是可能会有问题,比如更新数据库成功但更新缓存失败的情况,你当时有考虑过怎么处理这种异常不? + +8.我接着问你 SproutClaw 项目,你说开发了聚合搜索 MCP 工具扩展 Agent 网络搜索能力,能讲讲这个 MCP 聚合搜索具体是怎么实现的不? + +9.如果某个搜索工具返回的数据格式和预期不一样,你是怎么解决的呢? + +10.对 MCP 聚合搜索的实现逻辑很清晰。那在构建基于 Markdown 的轻量 RAG 知识库并封装为 Skills 这一块,你是怎么构建这个知识库,又如何利用它来减少 Agent 幻觉的呢? + +11.在对 Markdown 进行优化拆分时,有没有遇到一些特殊情况,像代码片段里包含注释或者 Markdown 中的特殊符号,你是怎么处理这些情况以保证拆分和重组后数据的准确性和可用性的呢? + +12.你谈谈对 Go 并发模型(Goroutine、Channel、GMP)的理解,以及在高并发场景下的调优思路吧。 + +13.你说说一次完整的 HTTP 请求在 Gin 框架中的处理链路,包括中间件、路由匹配、错误处理这些方面。 + +14.MySQL 索引失效通常有哪些原因?你能给出对应的优化思路不? + +15.Redis 分布式锁的实现方式有哪些?又如何防止死锁或锁失效造成的数据不一致呢? + +16.那我换个关于容器化部署的问题,在容器化部署中,你是如何确保服务平滑升级且不中断用户请求的呢? + +17.当你需要和前端、算法同学一起完成一个新功能时,你通常会怎么推进项目,又如何保证交付质量呢? + +18.如果和前端、算法同学对于功能实现方式有不同意见,你会怎么处理呢? \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/实习求职/面试经历/通用后端开发/6.4 JD YOUNG后端开发一面凉经.md b/mengyanote-backend/data/mengyanote/实习求职/面试经历/通用后端开发/6.4 JD YOUNG后端开发一面凉经.md new file mode 100644 index 0000000..854a830 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/面试经历/通用后端开发/6.4 JD YOUNG后端开发一面凉经.md @@ -0,0 +1,12 @@ +零售部门 +面试官很和蔼,不过他先介绍了自己,说之前在某研究所读博,方向是什么,然后去某大厂若干年,又来jd,我一听今天就要被拷打。 +1.先聊二十分钟科研,何意味 +2.讲一下MySQL 事务?回答后不断追问还有吗,直接想不起来了 +3.讲一下 MySQL 索引?追问还有吗 +4.RAG 项目,讲一下你的知识库实现流程,基于什么框架?向量数据库是怎么选择的?向量索引了解吗 +5.讲一下向量索引?HNSW、IVF这些 +5.RAG 中的 Redis 用来做什么?放在哪里? +6.文档怎么上传?原始文档需要存储吗?RAG 查询过程中访问原始文档了吗?需要访问吗?最后发给大模型的是什么? +7.你熟悉哪些系统?哪些框架? +8.rag项目分工是什么?其他同学负责什么任务? +无手撕 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/实习求职/项目经历/MengyaNoteRAG/mengya-rag项目简介.md b/mengyanote-backend/data/mengyanote/实习求职/项目经历/MengyaNoteRAG/mengya-rag项目简介.md new file mode 100644 index 0000000..0f33e74 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/项目经历/MengyaNoteRAG/mengya-rag项目简介.md @@ -0,0 +1,134 @@ +好的,我已经仔细查看了 `/shumengya/project/agent/mengya-rag` 项目。这是一个非常实用的个人知识库 RAG(检索增强生成)系统。让我为你详细介绍一下 (。・ω・。) + +## 项目概述 + +**萌芽 RAG 知识库**是一个轻量级的 Obsidian 笔记 RAG 项目,专门针对个人 Obsidian 笔记进行优化。它能够将你的 Markdown 笔记转化为可智能检索的知识库,并通过大模型提供问答服务。 + +## 技术架构 + +### 核心组件 +- **RAG 框架**: LlamaIndex +- **本地 Embedding**: `BAAI/bge-small-zh-v1.5`(通过 FastEmbed + ONNX 运行,无需 GPU) +- **大模型回答**: DeepSeek API(推荐 `deepseek-v4-flash`) +- **向量数据库**: SQLite + sqlite-vec(轻量级,无需额外服务) +- **检索方式**: BM25 关键词检索 + 向量语义检索的混合模式 + +### 项目结构 +``` +mengya-rag/ +├── data/ +│ ├── notes/ # Obsidian Markdown 笔记(从 bigmengya 同步) +│ └── index/bm25/ # 本地索引(SQLite 向量库 + 节点备份) +├── scripts/ # 同步、构建索引、问答脚本 +├── src/mengya_rag/ # 核心代码 +│ ├── config.py # 配置管理 +│ ├── markdown_chunker.py # Markdown 结构感知分块 +│ ├── indexing.py # 索引构建 +│ ├── retrieval.py # 检索、融合、盘点模式 +│ ├── qa.py # DeepSeek 生成回答 +│ └── cli.py # 命令行接口 +└── pyproject.toml # 项目配置 +``` + +## 核心功能 + +### 1. 智能 Markdown 分块 +不同于简单的字符切割,项目实现了**结构感知分块**: +- 识别 frontmatter 元数据 +- 按 H1-H6 标题层级组织分块 +- 代码块和表格整体保留,不跨块切割 +- 长块使用滑动窗口兜底 +- 每个 chunk 附带丰富的元数据(文件路径、标题路径、标签等) + +### 2. 混合检索系统 +- **普通问答模式**: BM25 + 向量检索 → RRF 融合 → 同文件去重 → 相关性过滤 +- **盘点列表模式**: 文件级目录检索,适合"有哪些"、"查一下"这类问题 +- **自动模式**: 根据问题类型自动选择检索方式 + +### 3. 命令行工具 +提供完整的 CLI 接口: +- `mengya-rag status`: 查看配置和索引状态 +- `mengya-rag search`: 只检索,不调用大模型 +- `mengya-rag context`: 返回可注入大模型的检索上下文 +- `mengya-rag ask`: 完成 RAG + DeepSeek 回答 +- `mengya-rag read`: 按路径读取完整笔记 +- `mengya-rag reindex`: 同步笔记并重建索引 + +## 使用场景 + +这个项目特别适合: +- **查找笔记**: "某个教程在哪里"、"某类笔记有哪些" +- **知识问答**: "WireGuard 怎么配置"、"Docker 常用命令有哪些" +- **内容总结**: "根据笔记总结某个主题" +- **目录浏览**: "列出博客文章"、"列出 Agent 安装教程" + +## 部署和配置 + +### 初始化 +```bash +cd /shumengya/project/agent/mengya-rag +cp .env.example .env +# 编辑 .env,填入 DEEPSEEK_API_KEY +uv sync +``` + +### 笔记同步 +笔记源:`bigmengya:/shumengya/docker/mengyanote-backend/data/mengyanote/` +```bash +./scripts/sync_notes.sh +``` + +### 索引构建 +```bash +./scripts/build_index.sh +``` + +### 使用示例 +```bash +# 查看状态 +uv run mengya-rag status --json + +# 普通问答 +uv run mengya-rag ask "Docker 常用命令有哪些" -k 4 --json + +# 盘点类查询 +uv run mengya-rag ask "查一下我目前博客文章有哪些" --json + +# 只检索不生成回答 +uv run mengya-rag search "WireGuard" --json +``` + +## 技术亮点 + +1. **轻量级部署**: 使用 SQLite + sqlite-vec,无需 Qdrant、Milvus 等外部数据库 +2. **本地 Embedding**: 使用 FastEmbed + ONNX,无需 GPU 和 PyTorch +3. **结构感知**: 充分利用 Markdown 结构,保留代码块和表格完整性 +4. **混合检索**: 结合关键词和语义检索,提高召回率 +5. **双模式检索**: 自动区分普通问答和盘点列表问题 +6. **Agent 友好**: 所有命令支持 `--json` 输出,便于程序调用 + +## 当前限制 + +- 单机 SQLite 向量库,数据量很大后需要扩展 +- 没有 reranker,复杂问题可能混入弱相关内容 +- embedding 模型是轻量中文模型,效果够用但不是最强 +- `build_index` 每次全量重建,暂无增量索引 +- 当前是 CLI 工具,没有 Web 界面 + +## 后续优化方向 + +- 增量索引,只重建变更文件 +- 加 reranker(如 `bge-reranker-v2-m3`) +- 给盘点类问题增加目录树模式 +- 增加 `--debug` 输出检索过程 +- 数据量变大后接 Qdrant + +## 索引规模参考 + +根据 README,当前索引规模: +- 分块数: 1802 +- 索引大小: 约 13M +- nodes.jsonl: 约 3.6M +- rag.sqlite3: 约 9.3M + +这是一个设计精良、实用性强的个人知识库系统,特别适合处理 Obsidian 笔记这类结构化文档。它的混合检索模式和结构感知分块是主要亮点 (`・ω・´) diff --git a/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的MCP工具应用情况.md b/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的MCP工具应用情况.md new file mode 100644 index 0000000..d0a0488 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的MCP工具应用情况.md @@ -0,0 +1,151 @@ +根据我的调研,我现在为你详细解释 MCP 及其在项目中的工作流程: + +--- + +## 什么是 MCP? + +**MCP**(Model Context Protocol)是 Anthropic 提出的一种**开放协议**,用于标准化 AI Agent 与外部工具、数据源之间的交互。它的核心目标是: + +- **统一接口**:让不同 AI 应用(如 Pi、Claude、Cursor 等)能一致地调用外部工具 +- **动态发现**:AI Agent 可以自动发现 MCP 服务器提供的工具,无需硬编码 +- **双向通信**:AI 向 MCP 服务器发请求,服务器返回结果,可以是文本、JSON 或结构化数据 + +**MCP 的三种核心能力:** +1. **Tools** — 可执行工具(如搜索、查询、创建 Issue) +2. **Resources** — 只读数据资源(如文件、文档) +3. **Prompts** — 预定义提示模板 + +--- + +## 项目中的 MCP 工作流程 + +### 1. 配置文件架构 + +``` +.pi/agent/ +├── mcp.json # MCP 服务器配置(启用/禁用) +├── mcp-cache.json # 工具缓存(缓存发现到的工具列表) +└── mcp-npx-cache.json # npx 包缓存路径 +``` + +**mcp.json** 配置示例: +```json +{ + "mcpServers": { + "tavily": { // 已启用的远程服务器 + "url": "https://mcp.tavily.com/mcp/?tavilyApiKey=..." + } + }, + "mcpServersDisabled": { + "cloudflare-search": { // 已禁用的服务器 + "command": "npx", + "args": ["-y", "@yrobot/cf-search-mcp"], + "env": { ... } + } + } +} +``` + +### 2. 服务器发现与缓存 + +**两种部署方式:** + +| 类型 | 配置方式 | 适用场景 | +|------|---------|---------| +| **远程 HTTP** | `url` 字段 | 第三方服务(如 Tavily、Google) | +| **本地 stdio** | `command` + `args` | 本地运行(如 `npx` 启动的 Node 包) | + +**发现流程:** +1. Pi 启动时读取 `mcp.json` +2. 对每个激活的服务器,连接并请求 **tools/list** 发现可用工具 +3. 将发现的工具元数据(名称、描述、参数 schema)缓存到 `mcp-cache.json` + +### 3. 工具管理与权限控制 + +通过 **WebUI** 提供精细控制: + +```typescript +// 前端类型定义 +interface McpServerInfo { + name: string; + enabled: boolean; + cached: boolean; + toolCount: number; + enabledToolCount: number; + tools: McpToolInfo[]; +} +``` + +**操作粒度:** +- **服务器级别**:启用/禁用整个 MCP Server +- **工具级别**:通过 `excludeTools` 排除特定工具 + +**API 路由:** +``` +POST /api/settings/mcp/server/toggle // 启用/禁用服务器 +POST /api/settings/mcp/tool/toggle // 启用/禁用单个工具 +GET /api/settings // 获取所有 MCP 配置 +``` + +### 4. 工具调用流程 + +当 AI Agent 需要调用 MCP 工具时: + +``` +1. 用户请求 → 系统提示词包含可用 MCP 工具列表 +2. AI 判断 → 选择要调用的工具(如 tavily_search) +3. 参数构造 → 按 inputSchema 生成 JSON 参数 +4. MCP 调用 → 通过 mcp 工具发送到对应服务器 +5. 结果返回 → 服务器返回结果,AI 解析并继续处理 +``` + +### 5. 项目中实际部署的 MCP 服务器 + +| 服务器 | 状态 | 提供能力 | +|--------|------|---------| +| **Tavily** | ✅ 启用 | `tavily_search`、`tavily_extract`、`tavily_crawl`、`tavily_map`、`tavily_research` | +| **Cloudflare Search** | ❌ 禁用 | `web_search`、`search` | + +--- + +## 项目中的 MCP 代码实现 + +**后端设置管理**(`webui/backend/settings/mcp-settings.ts`): +- 读写 `mcp.json` 配置 +- 管理 `mcpServers`(启用)和 `mcpServersDisabled`(禁用) +- 从 `mcp-cache.json` 读取工具缓存 +- 支持 `excludeTools` 字段控制工具级权限 + +**WebUI 路由**(`webui/backend/routes/settings.ts`): +- `/api/settings/mcp/server/toggle` — 切换服务器状态 +- `/api/settings/mcp/tool/toggle` — 切换工具状态 +- 修改后触发 `reload` 让 Agent 重新加载配置 + +**前端 API**(`webui/frontend/src/api/settings.ts`): +- `toggleMcpServer(server, enabled)` — 切换服务器 +- `toggleMcpTool(server, tool, enabled)` — 切换工具 + +--- + +## 与 Pi 原生工具的对比 + +| 特性 | MCP | Pi 原生工具 | +|------|-----|------------| +| 协议 | 标准化(Anthropic 主导) | Pi 自定义 | +| 工具来源 | 外部服务器(第三方) | 内置(read, bash, edit, write) | +| 发现方式 | 动态发现(tools/list) | 硬编码在系统提示 | +| 配置 | `mcp.json` + `mcp-cache.json` | `settings.json` | + +**项目设计哲学**:Pi 本身**不强制依赖 MCP**,更推崇通过 **Skills**(Markdown 说明文件)构建本地工具。但提供 **MCP Gateway** 作为扩展,让用户可以按需接入外部 MCP 生态。 + +--- + +## 总结 + +MCP 在项目中是一个**可选的扩展机制**,而非核心依赖。它通过: +- `mcp.json` 配置服务器 +- `mcp-cache.json` 缓存工具发现结果 +- WebUI 提供可视化权限控制 +- 标准 JSON-RPC 协议与外部服务器通信 + +这套架构让 Pi 可以安全地接入 Tavily 搜索、Cloudflare 等第三方 MCP 服务,同时保持对工具粒度的精细控制。 diff --git a/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的上下文工程详情.md b/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的上下文工程详情.md new file mode 100644 index 0000000..5a88dd1 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的上下文工程详情.md @@ -0,0 +1,452 @@ +我已经深入分析了 sproutclaw 项目的源码。让我为你详细解释这个项目的上下文工程实现。 + +--- + +# SproutClaw 上下文工程详解 + +## 一、什么是上下文工程 + +**上下文工程**(Context Engineering)是 AI Agent 设计中的核心概念,指的是如何**构建和管理每次发送给大模型的完整上下文**(system prompt + 历史消息 + 工具定义 + 项目上下文),以最大化模型的任务完成能力。 + +--- + +## 二、SproutClaw 上下文工程的核心架构 + +### 2.1 系统提示词构建流程 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ buildSystemPrompt() │ +├─────────────────────────────────────────────────────────────┤ +│ 1. 自定义系统提示词(来自 SYSTEM.md 或 SDK 配置) │ +│ 2. 工具列表 + 每个工具的单行摘要 │ +│ 3. 指导原则(guidelines) │ +│ 4. 项目上下文文件(AGENTS.md / CLAUDE.md) │ +│ 5. 技能列表(Skills XML 格式) │ +│ 6. 当前日期 + 工作目录 │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 2.2 核心代码:system-prompt.ts + +```typescript +// 核心构建函数 +export function buildSystemPrompt(options: BuildSystemPromptOptions): string { + // 1. 自定义系统提示词(来自 SYSTEM.md) + if (customPrompt) { + prompt = customPrompt; + } + + // 2. 项目上下文文件(AGENTS.md / CLAUDE.md) + // 从当前目录向上遍历,找到所有 AGENTS.md 文件 + for (const { path, content } of contextFiles) { + prompt += `${content}`; + } + + // 3. 技能列表(XML 格式) + prompt += formatSkillsForPrompt(skills); + + // 4. 日期和工作目录 + prompt += `\nCurrent date: ${date}`; + prompt += `\nCurrent working directory: ${cwd}`; + + return prompt; +} +``` + +--- + +## 三、每次发送给大模型的完整上下文 + +### 3.1 System Prompt(系统提示词) + +系统提示词包含以下**6个核心部分**: + +#### Part 1:角色定义 + 工具列表 +``` +You are an expert coding assistant operating inside pi, a coding agent harness. + +Available tools: +- read: Read the contents of a file... +- bash: Execute a bash command... +- edit: Make precise file edits... +- write: Write content to a file... +``` + +#### Part 2:指导原则(Guidelines) +``` +Guidelines: +- Be concise in your responses +- Show file paths clearly when working with files +- Use grep/find/ls tools over bash for file exploration +- [扩展注册的额外 guidelines] +``` + +#### Part 3:Pi 文档指引(当用户询问 Pi 自身功能时) +``` +Pi documentation (read only when the user asks about pi itself): +- Main documentation: /path/to/README.md +- Additional docs: /path/to/docs +- Examples: /path/to/examples +``` + +#### Part 4:项目上下文文件(Project Context) +```xml + + + ## 开发规范 + - 代码风格要求... + - Git 提交规范... + - 测试要求... + + + + ## 项目特定配置 + - 部署环境... + - 数据库配置... + + +``` + +#### Part 5:技能列表(Skills XML) +```xml + + + frontend-design + Guidance for distinctive visual design... + /path/to/SKILL.md + + + quark-sign-skill + 夸克网盘自动签到... + /path/to/SKILL.md + + +``` + +#### Part 6:时间戳 + 工作目录 +``` +Current date: 2026-06-16 +Current working directory: /shumengya/project/agent/sproutclaw +``` + +--- + +### 3.2 会话历史消息(Session Context) + +会话历史是通过 **SessionManager** 管理的,存储在 `.jsonl` 文件中: + +```typescript +// 消息类型 +type SessionEntry = + | SessionMessageEntry // 普通消息(user/assistant/toolResult) + | ThinkingLevelChangeEntry // 思考级别变更 + | ModelChangeEntry // 模型切换 + | CompactionEntry // 上下文压缩摘要 + | BranchSummaryEntry // 分支摘要 + | CustomEntry // 扩展自定义数据(不参与 LLM) + | CustomMessageEntry // 扩展消息(参与 LLM) + | LabelEntry // 用户标签 + | SessionInfoEntry // 会话元数据 +``` + +**构建发送给 LLM 的消息列表**: +```typescript +function buildSessionContext(entries, leafId, byId): SessionContext { + // 1. 从叶子节点回溯到根节点,构建路径 + const path = walkFromLeafToRoot(leafId); + + // 2. 如果存在压缩摘要,先发送摘要 + if (compaction) { + messages.push(createCompactionSummaryMessage(compaction.summary)); + } + + // 3. 添加保留的消息(从 firstKeptEntryId 开始) + messages.push(...keptMessages); + + return { messages, thinkingLevel, model }; +} +``` + +--- + +## 四、上下文管理的五大机制 + +### 4.1 项目上下文发现(Context Discovery) + +```typescript +// resource-loader.ts 中的 loadProjectContextFiles() +function loadProjectContextFiles(options) { + const contextFiles = []; + + // 1. 全局上下文:~/.pi/agent/AGENTS.md + const globalContext = loadContextFileFromDir(agentDir); + + // 2. 项目上下文:从 cwd 向上遍历所有目录 + let currentDir = cwd; + while (currentDir !== root) { + const contextFile = loadContextFileFromDir(currentDir); + if (contextFile) { + ancestorContextFiles.unshift(contextFile); // 保持从根到当前的顺序 + } + currentDir = parent(currentDir); + } + + return contextFiles; +} +``` + +**发现顺序**: +1. `~/.pi/agent/AGENTS.md`(全局) +2. `/project/AGENTS.md`(项目根) +3. `/project/src/AGENTS.md`(子目录) +4. `/project/src/components/AGENTS.md`(更深层) + +### 4.2 技能加载(Skills Loading) + +```typescript +// skills.ts 中的加载逻辑 +function loadSkills(options) { + // 1. 用户技能:~/.pi/agent/skills/ + // 2. 项目技能:.pi/skills/ + // 3. 显式路径:settings.json 中的 skills 数组 + // 4. 包技能:npm packages 的 skills/ 目录 + + // 发现规则: + // - 根目录的 .md 文件作为单独技能 + // - 包含 SKILL.md 的目录作为技能目录 +} +``` + +**技能在系统提示词中的呈现**: +```xml + + + skill-name + 技能描述... + /absolute/path/to/SKILL.md + + +``` + +### 4.3 提示模板(Prompt Templates) + +```typescript +// prompt-templates.ts +// 加载位置 +// 1. ~/.pi/agent/prompts/*.md +// 2. .pi/prompts/*.md +// 3. settings.json 中的 prompts 数组 + +// 模板格式 +--- +description: Review staged git changes +argument-hint: "" +--- +Review the staged changes (`git diff --cached`). Focus on: +- Bugs and logic errors +- Security issues +``` + +**使用方式**: +``` +/review # 展开模板 +/pr "修复登录bug" # 带参数展开 +``` + +### 4.4 上下文压缩(Compaction) + +当上下文超过阈值时,自动压缩旧内容: + +```typescript +// compaction.ts +function shouldCompact(contextTokens, contextWindow, settings) { + return contextTokens > contextWindow - settings.reserveTokens; +} + +// 压缩流程: +// 1. 从最新消息向前回溯 +// 2. 找到 keepRecentTokens(默认 20k tokens)的位置作为切点 +// 3. 调用 LLM 生成结构化摘要 +// 4. 保存 CompactionEntry,保留 firstKeptEntryId 之后的消息 +``` + +**压缩后的上下文结构**: +``` +System Prompt + Compaction Summary + Recent Messages +``` + +### 4.5 分支摘要(Branch Summarization) + +当在会话树中导航时,为被放弃的分支生成摘要: + +```typescript +// 当用户使用 /tree 导航到不同分支 +// 1. 找到公共祖先 +// 2. 收集要摘要的条目 +// 3. 生成摘要 +// 4. 保存 BranchSummaryEntry +``` + +--- + +## 五、上下文工程的核心设计原则 + +### 5.1 渐进式披露(Progressive Disclosure) + +``` +始终在上下文中: 按需加载: +├── 技能名称 + 描述 └── 完整 SKILL.md 内容 +├── 工具名称 + 单行摘要 └── 完整工具文档 +└── 项目规范摘要 └── 完整 AGENTS.md +``` + +### 5.2 分层上下文管理 + +``` +┌─────────────────────────────────────────────┐ +│ Layer 1: System Prompt(始终不变) │ +│ - 角色定义 + 工具列表 + 指导原则 │ +├─────────────────────────────────────────────┤ +│ Layer 2: Project Context(项目级) │ +│ - AGENTS.md 内容 │ +│ - Skills XML 列表 │ +├─────────────────────────────────────────────┤ +│ Layer 3: Session Context(会话级) │ +│ - 历史消息(可能被压缩) │ +│ - 当前工具调用结果 │ +├─────────────────────────────────────────────┤ +│ Layer 4: Turn Context(轮次级) │ +│ - 当前用户输入 │ +│ - 扩展注入的临时上下文 │ +└─────────────────────────────────────────────┘ +``` + +### 5.3 扩展点设计 + +扩展可以通过以下方式注入上下文: + +```typescript +// 1. 注册工具 +extension.registerTool({ + name: "my_tool", + promptSnippet: "单行描述", // 出现在系统提示词 + promptGuidelines: ["额外指导原则"], // 出现在系统提示词 +}); + +// 2. 注册事件处理器 +extension.on("before_agent_start", async (event) => { + // 修改系统提示词 + return { systemPrompt: modifiedPrompt }; + + // 注入自定义消息 + return { messages: [{ role: "custom", content: "..." }] }; +}); + +// 3. 注册资源发现 +extension.on("resources_discover", async () => { + return { + skillPaths: ["path/to/skills"], + promptPaths: ["path/to/prompts"], + }; +}); +``` + +--- + +## 六、配置文件体系 + +### 6.1 配置文件位置 + +| 文件 | 作用域 | 优先级 | +|------|--------|--------| +| `~/.pi/agent/settings.json` | 全局 | 低 | +| `.pi/settings.json` | 项目 | 高 | +| `~/.pi/agent/AGENTS.md` | 全局上下文 | - | +| `.pi/AGENTS.md` | 项目上下文 | - | +| `AGENTS.md` | 目录上下文 | - | + +### 6.2 上下文相关配置 + +```json +{ + // 技能和模板 + "skills": ["path/to/skills"], + "prompts": ["path/to/prompts"], + "packages": ["pi-skills"], + + // 压缩配置 + "compaction": { + "enabled": true, + "reserveTokens": 16384, + "keepRecentTokens": 20000 + }, + + // 分支摘要配置 + "branchSummary": { + "reserveTokens": 16384, + "skipPrompt": false + } +} +``` + +--- + +## 七、完整工作流程图 + +``` +用户输入: "帮我修复这个bug" + ↓ +┌──────────────────────────────────────────────────────────┐ +│ 1. 扩展 input 事件拦截 │ +│ └── 可能修改输入文本 │ +├──────────────────────────────────────────────────────────┤ +│ 2. 技能命令展开 (/skill:name) │ +│ └── 读取 SKILL.md 内容 │ +├──────────────────────────────────────────────────────────┤ +│ 3. 提示模板展开 (/template) │ +│ └── 替换参数占位符 │ +├──────────────────────────────────────────────────────────┤ +│ 4. before_agent_start 事件 │ +│ └── 扩展可以修改系统提示词 │ +├──────────────────────────────────────────────────────────┤ +│ 5. 构建完整上下文 │ +│ ├── System Prompt(6个部分) │ +│ ├── 历史消息(可能包含压缩摘要) │ +│ └── 当前用户消息 + 附件 │ +├──────────────────────────────────────────────────────────┤ +│ 6. 发送给 LLM │ +└──────────────────────────────────────────────────────────┘ + ↓ +┌──────────────────────────────────────────────────────────┐ +│ 7. LLM 返回响应 │ +│ ├── 文本回复 │ +│ └── 工具调用(read/bash/edit/write) │ +├──────────────────────────────────────────────────────────┤ +│ 8. 执行工具 + tool_result 事件 │ +│ └── 扩展可以拦截/修改结果 │ +├──────────────────────────────────────────────────────────┤ +│ 9. 检查是否需要压缩 │ +│ └── 上下文超阈值 → 自动生成摘要 │ +├──────────────────────────────────────────────────────────┤ +│ 10. 持久化到 Session │ +│ └── JSONL 文件追加 │ +└──────────────────────────────────────────────────────────┘ +``` + +--- + +## 八、总结 + +SproutClaw 的上下文工程实现了一套**分层、可扩展、渐进式**的上下文管理系统: + +| 机制 | 作用 | 触发时机 | +|------|------|---------| +| **Project Context** | 加载 AGENTS.md 等项目规范 | 启动时 | +| **Skills Discovery** | 发现并注册可用技能 | 启动时 + 重载时 | +| **Prompt Templates** | 提供可复用的提示模板 | 用户输入 `/` 时 | +| **Context Compaction** | 压缩过长的会话历史 | 上下文超阈值时 | +| **Branch Summarization** | 为放弃的分支生成摘要 | `/tree` 导航时 | +| **Extension Hooks** | 允许扩展注入/修改上下文 | 各个生命周期事件 | + +核心设计理念是:**始终在上下文中保持最少但足够的信息,让大模型能够高效地完成任务**。 diff --git a/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的工作流程是react吗,是否有plan-execute模式.md b/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的工作流程是react吗,是否有plan-execute模式.md new file mode 100644 index 0000000..630b278 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw的工作流程是react吗,是否有plan-execute模式.md @@ -0,0 +1,196 @@ +根据我对 sproutclaw 源码的分析,让我为你详细解释它的工作模式。 + +--- + +# SproutClaw 工作模式分析 + +## 一、核心结论 + +**SproutClaw 的核心工作流是 ReAct(Reasoning + Acting)模式**,不是 Plan-Execute 模式。 + +--- + +## 二、ReAct 模式的实现 + +### 2.1 核心循环(agent-loop.ts) + +```typescript +async function runLoop( + initialContext: AgentContext, + newMessages: AgentMessage[], + config: AgentLoopConfig, + signal: AbortSignal | undefined, + emit: AgentEventSink, + streamFn?: StreamFn, +): Promise { + let hasMoreToolCalls = true; + + // 内层循环:处理工具调用和 steering 消息 + while (hasMoreToolCalls || pendingMessages.length > 0) { + // 1. 流式获取 LLM 响应(Reasoning) + const message = await streamAssistantResponse(currentContext, config, signal, emit, streamFn); + + // 2. 检查是否有工具调用 + const toolCalls = message.content.filter((c) => c.type === "toolCall"); + + // 3. 执行工具调用(Acting) + if (toolCalls.length > 0) { + const executedToolBatch = await executeToolCalls(currentContext, message, config, signal, emit); + hasMoreToolCalls = !executedToolBatch.terminate; + + // 4. 工具结果返回给 LLM(Observing) + for (const result of toolResults) { + currentContext.messages.push(result); + } + } + + // 5. 检查是否应该停止 + if (await config.shouldStopAfterTurn?.({ message, toolResults, context: currentContext })) { + break; + } + + // 6. 获取 steering 消息(用户中途输入) + pendingMessages = (await config.getSteeringMessages?.()) || []; + } + + // 外层循环:检查 follow-up 消息 + const followUpMessages = (await config.getFollowUpMessages?.()) || []; + if (followUpMessages.length > 0) { + pendingMessages = followUpMessages; + continue; // 继续循环 + } +} +``` + +### 2.2 ReAct 循环图示 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ ReAct Loop │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ │ +│ │ 用户输入 │ │ +│ └──────┬──────┘ │ +│ ↓ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ Reasoning │───→│ Acting │───→│ Observing │ │ +│ │ (LLM 响应) │ │ (执行工具) │ │ (工具结果) │ │ +│ └─────────────┘ └─────────────┘ └──────┬──────┘ │ +│ ↑ │ │ +│ └─────────────────────────────────────┘ │ +│ 循环直到没有工具调用 │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 三、为什么不是 Plan-Execute 模式 + +### 3.1 Plan-Execute 模式的特征 + +| 特征 | Plan-Execute | SproutClaw (ReAct) | +|------|-------------|-------------------| +| **计划阶段** | 独立的计划步骤 | ❌ 没有 | +| **步骤列表** | 预定义的任务分解 | ❌ LLM 自主决定 | +| **执行阶段** | 按计划逐步执行 | ✅ 动态决定下一步 | +| **重新规划** | 失败时重新规划 | ❌ 直接重试或停止 | +| **步骤存储** | 保存计划状态 | ❌ 无计划状态 | + +### 3.2 SproutClaw 的决策方式 + +```typescript +// LLM 每次响应时自主决定下一步 +const message = await streamAssistantResponse(currentContext, config, signal, emit, streamFn); + +// LLM 可能返回: +// 1. 纯文本回复(任务完成) +// 2. 工具调用(需要执行操作) +// 3. 多个工具调用(并行执行) + +const toolCalls = message.content.filter((c) => c.type === "toolCall"); +// LLM 自己决定调用什么工具、传什么参数 +``` + +**没有预定义的计划列表**,LLM 在每次响应时动态决定下一步。 + +--- + +## 四、SproutClaw 的扩展机制 + +虽然核心是 ReAct,但 SproutClaw 提供了**扩展点**,可以实现类似 Plan-Execute 的行为: + +### 4.1 扩展钩子 + +```typescript +interface AgentLoopConfig { + // 1. 工具调用前拦截 + beforeToolCall?: (context: BeforeToolCallContext) => Promise; + + // 2. 工具调用后拦截 + afterToolCall?: (context: AfterToolCallContext) => Promise; + + // 3. 每轮结束后检查是否停止 + shouldStopAfterTurn?: (context: ShouldStopAfterTurnContext) => boolean | Promise; + + // 4. 下一轮开始前修改上下文 + prepareNextTurn?: (context: PrepareNextTurnContext) => AgentLoopTurnUpdate | undefined; + + // 5. 上下文转换 + transformContext?: (messages: AgentMessage[]) => Promise; +} +``` + +### 4.2 扩展可以实现的类似 Plan-Execute 行为 + +```typescript +// 示例:扩展可以实现任务分解 +extension.on("before_agent_start", async (event) => { + // 注入任务分解指令 + return { + systemPrompt: ` + ${event.systemPrompt} + + ## 任务分解规则 + 1. 首先分析任务 + 2. 制定执行计划 + 3. 逐步执行 + 4. 验证结果 + ` + }; +}); + +// 示例:扩展可以在工具调用前检查计划 +extension.on("tool_call", async (event) => { + // 检查是否符合计划 + if (!isPlanCompliant(event.toolName, event.input)) { + return { block: true, reason: "不符合执行计划" }; + } +}); +``` + +--- + +## 五、与其他 Agent 框架的对比 + +| 框架 | 核心模式 | 特点 | +|------|---------|------| +| **SproutClaw** | ReAct | 简单直接,LLM 自主决策 | +| **LangChain Agent** | ReAct | 类似,但更复杂 | +| **AutoGPT** | Plan-Execute | 显式的计划-执行循环 | +| **CrewAI** | 多 Agent 协作 | 角色分工,任务分配 | +| **MetaGPT** | SOP 驱动 | 标准化流程 | + +--- + +## 六、总结 + +| 问题 | 答案 | +|------|------| +| SproutClaw 是 ReAct 模式吗? | ✅ **是**,核心循环是典型的 ReAct | +| 有 Plan-Execute 模式吗? | ❌ **没有**,没有显式的计划阶段 | +| 能实现类似 Plan-Execute 吗? | ✅ **可以**,通过扩展钩子注入计划逻辑 | +| 为什么选择 ReAct? | 简单、灵活、LLM 自主决策能力强 | + +**SproutClaw 的设计哲学**:让 LLM 自己决定每一步做什么,而不是预先规划好所有步骤。这种模式更灵活,但依赖于 LLM 的推理能力。 diff --git a/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw简介.md b/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw简介.md new file mode 100644 index 0000000..e867e96 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/实习求职/项目经历/SproutClaw/SproutClaw简介.md @@ -0,0 +1,41 @@ +根据我的查看,`/shumengya/project/agent/sproutclaw` 是一个基于 [pi-mono](https://github.com/badlogic/pi-mono) 改造的 **Agent 助手项目**,主要面向服务器运维与开发工作。 + +## 项目概览 + +**定位**:服务器运维助手 + 开发协作助手 + Docker 部署助手 + +**技术栈**:Node.js (v22.19+) + TypeScript,使用 npm workspaces 管理的 monorepo 结构 + +## 核心包结构 + +| 包名 | 说明 | +|------|------| +| `packages/coding-agent` | 交互式 Agent CLI 与 TUI 主体(sproutclaw 定制) | +| `packages/agent` | Agent 运行时、工具调用和状态管理 | +| `packages/ai` | 多模型、多 provider 的 LLM 接入层 | +| `packages/tui` | 终端 UI 渲染库 | +| `packages/web-ui` | Web UI 示例/前端 | + +## 主要功能模块 + +- **LLM Provider 支持**:Anthropic、OpenAI、Google、Mistral、Amazon Bedrock、Cloudflare、Azure OpenAI 等 +- **WebUI 扩展**:`.pi/agent/extensions/webui/` 提供网页对话入口(React 前端 + HTTP 服务) +- **Skills 系统**:`.pi/agent/skills/` 目录下的技能包(SSH 操作、邮件、搜索、文档处理等) +- **本地化扩展**:中文启动页、命令帮助翻译等 + +## 项目状态 + +- **分支**:main 分支,与 origin/main 同步 +- **未提交变更**:有较多修改(主要是 WebUI 扩展和部分包的更新) +- **最近提交**:主要是 CI 修复、依赖固定、上游同步等 + +## 常用命令 + +```bash +npm install --ignore-scripts # 安装依赖 +npm run build # 构建 +npm run check # 代码检查 +./pi-test.sh # 本地测试运行 +``` + +项目整体结构清晰,是一个功能完善的 AI Agent 开发框架 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/技术原理解析/前后端交互相对路径和绝对路径区别.md b/mengyanote-backend/data/mengyanote/技术原理解析/前后端交互相对路径和绝对路径区别.md new file mode 100644 index 0000000..6b9fc42 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/技术原理解析/前后端交互相对路径和绝对路径区别.md @@ -0,0 +1,60 @@ +> 假如我有一个前后端项目 使用域名 nav.smyhub.com 后端使用nav.smyhub.com/api 然后我前端使用相对路径请求/api 和使用整个域名请求nav.smyhub.com/api 两个有没有什么区别 性能差异大不大 有没有什么影响 + +两种方式**基本没有性能差异**,但有一些细节值得了解。 + +## 相对路径 `/api` + +```js +fetch('/api/users') +``` + +- 浏览器自动补全为当前域名,即 `nav.smyhub.com/api/users` +- **没有额外的 DNS 解析**,因为连接已经建立 +- 代码更简洁,迁移域名时无需修改 + +## 完整域名 `nav.smyhub.com/api` + +```js +fetch('https://nav.smyhub.com/api/users') +``` + +- 浏览器同样请求同一个地址 +- 如果已有连接(HTTP/2 或 keep-alive),**会复用,不会重新建立** +- 实际上和相对路径走的是完全相同的网络路径 + +--- + +## 总结 + +|对比项|相对路径 `/api`|完整域名| +|---|---|---| +|性能|✅ 相同|✅ 相同| +|DNS 解析|无额外开销|无额外开销(复用连接)| +|跨域问题|✅ 不会触发 CORS|✅ 同域,也不会触发| +|可移植性|✅ 更好,换域名不用改代码|❌ 换域名需要全部修改| +|本地开发|⚠️ 需要配置代理(如 vite proxy)|❌ 本地会直接打到生产服务器| + +--- + +## 建议 + +**推荐用相对路径**,原因: + +1. 本地开发时配合 Vite/Webpack 代理更方便 +2. 换域名、迁移环境零成本 +3. 更符合前后端同域部署的惯例 + +如果你用 Vite,本地开发配置代理就能完美模拟: + +```js +// vite.config.js +server: { + proxy: { + '/api': 'http://localhost:8080' + } +} +``` + +生产环境 Nginx 同样直接转发 `/api` 即可,不需要任何代码变动。 + +[^1]: 假如我有一个前后端项目 使用域名 nav.smyhub.com 后端使用nav.smyhub.com/api 然后我前端使用相对路径请求/api 和使用整个域名请求nav.smyhub.com/api 两个有没有什么区别 性能差异大不大 有没有什么影响 diff --git a/mengyanote-backend/data/mengyanote/技术原理解析/localsend.md b/mengyanote-backend/data/mengyanote/技术原理解析/项目分析/LocalSend.md similarity index 100% rename from mengyanote-backend/data/mengyanote/技术原理解析/localsend.md rename to mengyanote-backend/data/mengyanote/技术原理解析/项目分析/LocalSend.md diff --git a/mengyanote-backend/data/mengyanote/技术原理解析/Rusted Warfare.md b/mengyanote-backend/data/mengyanote/技术原理解析/项目分析/Rusted Warfare.md similarity index 100% rename from mengyanote-backend/data/mengyanote/技术原理解析/Rusted Warfare.md rename to mengyanote-backend/data/mengyanote/技术原理解析/项目分析/Rusted Warfare.md diff --git a/mengyanote-backend/data/mengyanote/数据库/MySQL/MySQL基础语法总结.md b/mengyanote-backend/data/mengyanote/数据库/MySQL/MySQL基础语法总结.md new file mode 100644 index 0000000..13a97c0 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/MySQL/MySQL基础语法总结.md @@ -0,0 +1,199 @@ + +## 一、数据库操作 + +```sql +-- 创建数据库 +CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- 查看数据库 +SHOW DATABASES; + +-- 选择数据库 +USE db_name; + +-- 删除数据库 +DROP DATABASE db_name; +``` + +## 二、表操作 + +```sql +-- 创建表 +CREATE TABLE users ( + id INT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(50) NOT NULL, + email VARCHAR(100) UNIQUE, + age INT DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 查看表结构 +DESC users; +SHOW CREATE TABLE users; + +-- 修改表 +ALTER TABLE users ADD COLUMN phone VARCHAR(20); +ALTER TABLE users MODIFY COLUMN age TINYINT; +ALTER TABLE users DROP COLUMN phone; +ALTER TABLE users RENAME TO new_users; + +-- 删除表 +DROP TABLE users; +TRUNCATE TABLE users; -- 清空数据,保留结构 +``` + +## 三、数据操作 (CRUD) + +### INSERT +```sql +INSERT INTO users (name, email, age) VALUES ('张三', 'zhangsan@mail.com', 25); +INSERT INTO users (name, email) VALUES ('李四', 'lisi@mail.com'), ('王五', 'wangwu@mail.com'); +``` + +### SELECT +```sql +-- 基本查询 +SELECT * FROM users; +SELECT name, email FROM users; + +-- 条件过滤 +SELECT * FROM users WHERE age > 18; +SELECT * FROM users WHERE name LIKE '张%'; +SELECT * FROM users WHERE age BETWEEN 18 AND 30; +SELECT * FROM users WHERE id IN (1, 2, 3); + +-- 排序 +SELECT * FROM users ORDER BY age DESC, name ASC; + +-- 分页 +SELECT * FROM users LIMIT 10 OFFSET 0; -- 或 LIMIT 0, 10 + +-- 聚合 +SELECT COUNT(*), AVG(age), MAX(age), MIN(age), SUM(age) FROM users; +SELECT age, COUNT(*) FROM users GROUP BY age HAVING COUNT(*) > 1; + +-- 去重 +SELECT DISTINCT age FROM users; +``` + +### UPDATE +```sql +UPDATE users SET age = 26 WHERE name = '张三'; +UPDATE users SET age = age + 1; -- 所有人年龄+1 +``` + +### DELETE +```sql +DELETE FROM users WHERE id = 1; +DELETE FROM users; -- 清空表(逐行删除,可回滚) +``` + +## 四、常用约束 + +| 约束 | 作用 | +|------|------| +| `PRIMARY KEY` | 主键,唯一标识 | +| `FOREIGN KEY` | 外键,关联其他表 | +| `UNIQUE` | 唯一约束 | +| `NOT NULL` | 非空 | +| `DEFAULT` | 默认值 | +| `CHECK` | 检查约束(MySQL 8.0+ 才生效) | +| `AUTO_INCREMENT` | 自增 | + +## 五、JOIN 连表查询 + +```sql +-- INNER JOIN (交集) +SELECT u.name, o.order_no +FROM users u +INNER JOIN orders o ON u.id = o.user_id; + +-- LEFT JOIN (左表全部 + 右表匹配) +SELECT u.name, o.order_no +FROM users u +LEFT JOIN orders o ON u.id = o.user_id; + +-- RIGHT JOIN (右表全部 + 左表匹配) +SELECT u.name, o.order_no +FROM users u +RIGHT JOIN orders o ON u.id = o.user_id; +``` + +## 六、索引 + +```sql +-- 创建索引 +CREATE INDEX idx_name ON users(name); +CREATE UNIQUE INDEX idx_email ON users(email); +CREATE INDEX idx_name_age ON users(name, age); -- 复合索引 + +-- 删除索引 +DROP INDEX idx_name ON users; + +-- 查看索引 +SHOW INDEX FROM users; +``` + +## 七、事务 + +```sql +START TRANSACTION; + +UPDATE accounts SET balance = balance - 100 WHERE id = 1; +UPDATE accounts SET balance = balance + 100 WHERE id = 2; + +COMMIT; -- 提交 +ROLLBACK; -- 回滚 +``` + +**ACID 特性**:原子性、一致性、隔离性、持久性。 + +## 八、常用函数 + +```sql +-- 字符串 +CONCAT('a', 'b'); LENGTH('abc'); UPPER('abc'); +SUBSTRING('hello', 1, 2); TRIM(' a '); + +-- 时间日期 +NOW(); CURDATE(); CURTIME(); +DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); +DATEDIFF('2025-01-01', '2024-01-01'); + +-- 条件 +IF(age >= 18, '成年', '未成年'); +CASE WHEN age < 18 THEN '少年' WHEN age < 60 THEN '中年' ELSE '老年' END; + +-- 数学 +ROUND(1.234, 2); CEIL(1.2); FLOOR(1.9); ABS(-5); +``` + +## 九、子查询 + +```sql +-- WHERE 子查询 +SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 100); + +-- 标量子查询 +SELECT name, (SELECT AVG(age) FROM users) AS avg_age FROM users; + +-- EXISTS 子查询 +SELECT * FROM users u WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id); +``` + +## 十、常用数据类型 + +| 类型 | 说明 | +|------|------| +| `INT` / `TINYINT` | 整数 | +| `BIGINT` | 大整数 | +| `DECIMAL(10,2)` | 精确小数(金额用这个) | +| `VARCHAR(n)` | 变长字符串 | +| `TEXT` | 长文本 | +| `DATE` / `DATETIME` / `TIMESTAMP` | 日期时间 | +| `JSON` | JSON 类型(MySQL 5.7+) | +| `BLOB` | 二进制数据 | + +--- + +**快速记忆口诀**:`INSERT 增,DELETE 删,UPDATE 改,SELECT 查`,再加个 `JOIN` 来连表 diff --git a/mengyanote-backend/data/mengyanote/数据库/MySQL/MySQL的内置系统数据库.md b/mengyanote-backend/data/mengyanote/数据库/MySQL/MySQL的内置系统数据库.md new file mode 100644 index 0000000..061584a --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/MySQL/MySQL的内置系统数据库.md @@ -0,0 +1,112 @@ + +--- + +## information_schema + +**是什么**:MySQL 的元数据(数据字典)视图库,保存了所有数据库、表、列、索引、权限等结构信息。 + +**特点**: +- 只读,不能对里面的表执行 `INSERT` / `UPDATE` / `DELETE` +- 实际是内存中的虚拟表(视图),并非物理存储 + +**常用查询**: + +```sql +-- 查看所有数据库 +SELECT SCHEMA_NAME FROM information_schema.SCHEMATA; + +-- 查看某张表的结构 +SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT +FROM information_schema.COLUMNS +WHERE TABLE_SCHEMA = 'mengyastore' AND TABLE_NAME = 'users'; + +-- 查看所有索引 +SELECT * FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = 'mengyastore'; + +-- 查看当前所有连接 +SELECT * FROM information_schema.PROCESSLIST; +``` + +**典型用途**:程序自动生成文档、ORM 反向工程、数据库迁移检查。 + +--- + +## performance_schema + +**是什么**:MySQL 5.5+ 引入的性能监控与诊断数据库,用于收集服务器执行时的细粒度指标。 + +**特点**: +- 只读,数据来自 MySQL 内部的事件采集器 +- 默认开启(`performance_schema=ON`),会消耗少量性能 +- 比 `information_schema` 更侧重"运行时的行为"而非"静态结构" + +**常用场景**: + +```sql +-- 查看最慢的 SQL(按总等待时间排序) +SELECT DIGEST_TEXT, COUNT_STAR, SUM_TIMER_WAIT +FROM performance_schema.events_statements_summary_by_digest +ORDER BY SUM_TIMER_WAIT DESC +LIMIT 10; + +-- 查看表 I/O 瓶颈 +SELECT * FROM performance_schema.table_io_waits_summary_by_table +WHERE TABLE_SCHEMA = 'mengyastore'; + +-- 查看索引使用情况 +SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage +WHERE TABLE_SCHEMA = 'mengyastore'; +``` + +**典型用途**:定位慢查询、索引未命中、锁等待、IO 瓶颈。 + +--- + +## sys + +**是什么**:MySQL 5.7+ 引入,基于 `performance_schema` 和 `information_schema` 封装的一组**易用视图和存储过程**,相当于给两个底层系统库加了一层"快捷操作"。 + +**特点**: +- 只读视图 + 辅助存储过程 +- 不用再写复杂的底层查询,直接调用封装好的视图 + +**常用查询**: + +```sql +-- 查看按 IO 排序的热表 +SELECT * FROM sys.io_global_by_file_by_bytes LIMIT 10; + +-- 查看当前会话和锁等待 +SELECT * FROM sys.session; +SELECT * FROM sys.innodb_lock_waits; + +-- 查看慢查询 +SELECT * FROM sys.statement_analysis ORDER BY avg_latency DESC LIMIT 10; + +-- 查看表空间大小 +SELECT * FROM sys.schema_table_statistics WHERE table_schema = 'mengyastore'; + +-- 格式化查看 InnoDB 状态 +CALL sys.ps_setup_enable_instrument('wait/io/file/innodb/innodb_data_file'); +``` + +--- + +## 三者关系总结 + +``` +information_schema ───── 静态元数据(表结构、列、约束等) + ↓ +performance_schema ───── 动态运行指标(事件、锁、IO、等待) + ↓ +sys ───── 封装的快捷视图(让你少写 SQL) +``` + +打个比方: + +| 类比 | 对应 | +|------|------| +| 图书馆的**图书目录卡** | `information_schema` | +| 门口借阅**刷卡记录仪** | `performance_schema` | +| 前台直接问"今天哪本书被借最多"的**快捷查询窗** | `sys` | + diff --git a/mengyanote-backend/data/mengyanote/数据库/MySQL/Typora_Hook_Log.txt b/mengyanote-backend/data/mengyanote/数据库/MySQL/Typora_Hook_Log.txt new file mode 100644 index 0000000..ef3bfae --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/MySQL/Typora_Hook_Log.txt @@ -0,0 +1,198 @@ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync 重定向 D:\WindowsApp\Typora\resources\app\atom.compiled.dist.jsc --> D:\WindowsApp\Typora\resources\app.bak\atom.compiled.dist.jsc +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.openSync D:\WindowsApp\Typora\resources\app.bak\atom.compiled.dist.jsc +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\hjson\lib\hjson.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\util\assign.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\fs\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\node_modules\universalify\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\graceful-fs\graceful-fs.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\graceful-fs\polyfills.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\graceful-fs\legacy-streams.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\graceful-fs\clone.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\copy\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\copy\copy.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\copy\ncp.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\util\utimes.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\mkdirs\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\mkdirs\mkdirs.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\mkdirs\win32.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\mkdirs\mkdirs-sync.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\path-exists\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\copy-sync\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\copy-sync\copy-sync.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\copy-sync\copy-file-sync.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\util\buffer.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\remove\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\remove\rimraf.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\json\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\json\jsonfile.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\node_modules\jsonfile\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\json\output-json-sync.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\json\output-json.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\move\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\move-sync\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\empty\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\ensure\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\ensure\file.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\ensure\link.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\ensure\symlink.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\ensure\symlink-paths.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\ensure\symlink-type.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-extra\lib\output\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\electron-fetch\lib\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\electron-fetch\node_modules\encoding\lib\encoding.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\iconv-lite\lib\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\iconv-lite\node_modules\safer-buffer\safer.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\iconv-lite\lib\bom-handling.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\iconv-lite\lib\streams.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync C:\Users\smy\AppData\Roaming\Typora/conf/conf.user.json +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\lib\fs-plus.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\underscore-plus\lib\underscore-plus.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\underscore\underscore-node.cjs +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\underscore\underscore-node-f.cjs +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\async\lib\async.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\mkdirp\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\rimraf\rimraf.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\glob\glob.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\fs.realpath\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\fs.realpath\old.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\minimatch\minimatch.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\brace-expansion\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\concat-map\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\balanced-match\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\inherits\inherits.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\path-is-absolute\index.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\glob\sync.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\glob\common.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\inflight\inflight.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\wrappy\wrappy.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\fs-plus\node_modules\once\once.js +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.statSync d:\windowsapp\typora\typora.exe +------------------ +[2026/5/29 12:09:09] [Log] [🛡️ fsHook] 程序试图 fs.statSync D:\WINDOWSAPP\TYPORA\TYPORA.EXE +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.open C:\Users\smy\AppData\Roaming\Typora/typora.log +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\lowdb\lib\main.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\lowdb\node_modules\lodash\lodash.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\lowdb\node_modules\is-promise\index.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\lowdb\adapters\FileSync.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\lowdb\adapters\Base.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\lowdb\adapters\_stringify.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync C:\Users\smy\AppData\Roaming\Typora\profile.data +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync C:\Users\smy\AppData\Roaming\Typora\history.data +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\native-reg\lib\index.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.statSync D:\SmyProjects\Frontend-Backend\mengyanote\mengyanote-backend\data\mengyanote\数据库\MySQL\控制台连接MySQL教程.md +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFile D:\WindowsApp\Typora\resources\locales\zh-Hans.lproj\Menu.json +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\electron-progressbar\source\index.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFileSync D:\WindowsApp\Typora\resources\node_modules.asar\electron-progressbar\node_modules\extend\index.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFile D:\WindowsApp\Typora\resources\locales\zh-Hans.lproj\Menu.json +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.readFile C:\Users\smy\AppData\Roaming\Typora\typora-dictionaries/user-dict.json +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.stat C:\Users\smy\AppData\Local\Temp\Typora +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.stat C:\Users\smy\AppData\Roaming\Typora\backups +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.open C:\Users\smy\AppData\Roaming\Typora/backups/sum +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.stat C:\Users\smy\AppData\Roaming\Typora\backups +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook] 程序试图 fs.open C:\Users\smy\AppData\Roaming\Typora/backups/sum +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook/Promises] 程序试图 fs.promises.readFile 重定向 D:\WindowsApp\Typora\resources\app/package.json --> D:\WindowsApp\Typora\resources\app.bak\package.json +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook/Promises] 程序试图 fs.promises.readFile 重定向 D:\WindowsApp\Typora\resources\app/launch.dist.js --> D:\WindowsApp\Typora\resources\app.bak\launch.dist.js +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook/Promises] 程序试图 fs.promises.readFile 重定向 D:\WindowsApp\Typora\resources\app/../page-dist/license.html --> D:\WindowsApp\Typora\resources\app.bak\../page-dist/license.html +------------------ +[2026/5/29 12:09:10] [Log] [🛡️ fsHook/Promises] 程序试图 fs.promises.readFile 重定向 D:\WindowsApp\Typora\resources\app/../page-dist/static/js/LicenseIndex.180dd4c7.5b58fa97.js --> D:\WindowsApp\Typora\resources\app.bak\../page-dist/static/js/LicenseIndex.180dd4c7.5b58fa97.js +------------------ +[2026/5/29 12:09:13] [Log] [🛡️ fsHook] 程序试图 fs.readFile D:\WindowsApp\Typora\resources\locales\zh-Hans.lproj\Panel.json +------------------ +[2026/5/29 12:09:13] [Log] [🛡️ fsHook] 程序试图 fs.statSync C:\Users\smy\AppData\Roaming\Typora\backups +------------------ +[2026/5/29 12:09:13] [Log] [🛡️ fsHook] 程序试图 fs.statSync C:\Users\smy\AppData\Roaming\Typora/typora.log +------------------ diff --git a/mengyanote-backend/data/mengyanote/数据库/MySQL/控制台连接MySQL教程.md b/mengyanote-backend/data/mengyanote/数据库/MySQL/控制台连接MySQL教程.md index 09bb8a5..6fba5d0 100644 --- a/mengyanote-backend/data/mengyanote/数据库/MySQL/控制台连接MySQL教程.md +++ b/mengyanote-backend/data/mengyanote/数据库/MySQL/控制台连接MySQL教程.md @@ -1,49 +1,121 @@ -## 1️⃣ 本地终端进入并进行密码验证 - -### 1.1 使用用户名和密码登录本地 MySQL - -在 Debian 服务器本机,通过终端使用 MySQL 客户端连接数据库: +## 一、命令行连接 ```bash +# 基本连接 mysql -u root -p + +# 指定主机和端口(默认 127.0.0.1:3306) +mysql -h 192.168.1.100 -P 3306 -u root -p + +# 直接指定数据库 +mysql -u root -p db_name + +# 连接后查看当前用户和数据库 +mysql> SELECT USER(), DATABASE(); ``` -- `-u root`:指定登录用户 -- `-p`:表示需要进行密码验证 -执行后,系统会提示: +> 输入 `-p` 后回车会提示输入密码,密码不回显,更安全。 + +## 二、常见客户端工具 + +| 工具 | 平台 | 特点 | +|------|------|------| +| **MySQL Workbench** | 全平台 | 官方 GUI,可视化建表、ER 图 | +| **DBeaver** | 全平台 | 免费通用数据库管理,支持多种数据库 | +| **Navicat** | 全平台(付费) | 功能强大,界面美观 | +| **HeidiSQL** | Windows | 轻量、免费 | +| **TablePlus** | macOS / Windows | 界面简洁现代 | +| **Sequel Ace** | macOS | 免费开源,前身 Sequel Pro | +| **phpMyAdmin** | Web | 基于 PHP 的 Web 管理工具 | + +## 三、编程语言连接 + +### Python (`pymysql` / `mysql-connector-python`) + +```python +import pymysql + +conn = pymysql.connect( + host='localhost', + port=3306, + user='root', + password='your_password', + database='db_name', + charset='utf8mb4' +) + +cursor = conn.cursor() +cursor.execute('SELECT * FROM users') +rows = cursor.fetchall() +print(rows) +cursor.close() +conn.close() ``` -Enter password: + +**推荐方案**:实际项目中建议用 `SQLAlchemy` ORM,避免手写裸 SQL 拼接。 + +### Node.js (`mysql2`) + +```js +const mysql = require('mysql2/promise'); + +const conn = await mysql.createConnection({ + host: 'localhost', + port: 3306, + user: 'root', + password: 'your_password', + database: 'db_name' +}); + +const [rows] = await conn.execute('SELECT * FROM users'); +console.log(rows); +await conn.end(); ``` -输入对应用户的 MySQL 密码(输入时不会显示),验证成功后即可进入 MySQL 控制台: ---- +### PHP -### 1.2 使用 sudo 方式本地登录(仅限本机) +```php +$conn = new mysqli('localhost', 'root', 'password', 'db_name'); +if ($conn->connect_error) die("连接失败: " . $conn->connect_error); +$result = $conn->query("SELECT * FROM users"); +while ($row = $result->fetch_assoc()) { print_r($row); } +$conn->close(); +``` -在 Debian 默认安装的 MySQL 环境中,`root` 用户可能使用 **unix_socket** 认证插件,可直接通过系统权限登录: +### Go + +```go +import "database/sql" +import _ "github.com/go-sql-driver/mysql" + +db, _ := sql.Open("mysql", "root:password@tcp(localhost:3306)/db_name?charset=utf8mb4") +rows, _ := db.Query("SELECT * FROM users") +``` + +## 四、通过 SSH 隧道连接(远程服务器内网 MySQL) + +当 MySQL 不对外暴露端口时,通过 SSH 跳板机转发: ```bash -sudo mysql +# 本地 3307 → 远程服务器 localhost:3306 +ssh -L 3307:localhost:3306 user@remote_host -N + +# 然后连接本机的 3307 端口 +mysql -h 127.0.0.1 -P 3307 -u root -p ``` -- 该方式 **不需要输入 MySQL 密码** -- 仅适用于本机登录 -- 不适用于远程连接或普通用户 ---- +## 五、常见连接错误及解决 -## 2️⃣ 远程通过密码连接 MySQL +| 错误 | 原因 | 解决 | +|------|------|------| +| `Access denied for user` | 密码错误 / 用户无权限 | 检查密码,或 `GRANT` 授权 | +| `Can't connect to MySQL server` | MySQL 未启动 / 端口不对 / 防火墙拦截 | `systemctl start mysqld`,检查端口和防火墙 | +| `Host 'xxx' is not allowed to connect` | 用户未授权远程连接 | `GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY '密码'; FLUSH PRIVILEGES;` | +| `Authentication plugin 'caching_sha2_password'` | MySQL 8 默认插件兼容问题 | 连接时指定 `--default-auth=mysql_native_password` 或修改用户插件 | -### 2.1 使用密码从远程主机连接 MySQL +## 六、查看当前所有连接 -```bash -mysql -h <服务器IP> -P 3306 -u 用户名 -p -mysql -h 10.0.0.100 -P 3306 -u root -p +```sql +SHOW PROCESSLIST; ``` - -参数说明: -- `-h`:MySQL 服务器 IP 地址 -- `-P`:MySQL 端口号(默认 `3306`) -- `-u`:数据库用户名 -- `-p`:启用密码验证(回车后输入密码) ---- diff --git a/mengyanote-backend/data/mengyanote/数据库/MySQL/有趣的代码片段.md b/mengyanote-backend/data/mengyanote/数据库/MySQL/有趣的代码片段.md new file mode 100644 index 0000000..744cbbd --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/MySQL/有趣的代码片段.md @@ -0,0 +1,5 @@ +```sql +SELECT * FROM girls +WHERE age BETWEEN 20 AND 22 +AND boyfriend IS NULL +``` \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server常用语法操作.md b/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server常用语法操作.md new file mode 100644 index 0000000..b3c5f04 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server常用语法操作.md @@ -0,0 +1,182 @@ + +### 1. 基础查询(DQL - Data Query Language) + +```sql +-- 基本查询 +SELECT * FROM 表名; +SELECT 列1, 列2 AS 别名 FROM 表名 WHERE 条件 ORDER BY 列 DESC; + +-- 去重、限制行数 +SELECT DISTINCT 列 FROM 表; +SELECT TOP 10 * FROM 表 ORDER BY id DESC; +SELECT TOP 50 PERCENT * FROM 表; + +-- 模糊查询 +WHERE 列 LIKE '张%' -- 以张开头 +WHERE 列 LIKE '%工程师%' -- 包含 +WHERE 列 LIKE '[A-Z]%' -- 正则风格范围 +WHERE 列 LIKE '[^0-9]%' -- 非数字开头 + +-- 日期范围 +WHERE 创建时间 >= '2025-01-01' + AND 创建时间 < '2025-02-01'; + +-- 分页(推荐 OFFSET-FETCH) +SELECT * FROM 表 +ORDER BY id +OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY; +``` + +### 2. 条件与连接 + +```sql +-- 多条件 +WHERE (条件1 OR 条件2) AND 条件3; + +-- 连接 +INNER JOIN 表2 ON 表1.id = 表2.id +LEFT JOIN 表2 ON ... -- 左外连接 +RIGHT JOIN ... +FULL OUTER JOIN ... + +-- 交叉连接(笛卡尔积) +CROSS JOIN 表2 + +-- APPLY(常用场景:取Top N) +CROSS APPLY (SELECT TOP 5 * FROM 子表 WHERE ... ORDER BY ...) AS t +OUTER APPLY ... +``` + +### 3. 聚合与分组 + +```sql +SELECT + 部门, + COUNT(*) AS 人数, + SUM(金额) AS 总金额, + AVG(金额) AS 平均, + MAX(金额) AS 最高, + MIN(金额) AS 最低 +FROM 表 +GROUP BY 部门 +HAVING COUNT(*) > 10; -- 对分组结果过滤 +``` + +**窗口函数(非常推荐)**: +```sql +ROW_NUMBER() OVER (PARTITION BY 部门 ORDER BY 金额 DESC) AS 排名 +RANK(), DENSE_RANK() +SUM(金额) OVER (PARTITION BY 部门) AS 部门总计 +SUM(金额) OVER (ORDER BY 日期 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 累计 +``` + +### 4. 数据操作(DML) + +```sql +-- 插入 +INSERT INTO 表 (列1,列2) VALUES (1,'张三'); +INSERT INTO 表 SELECT * FROM 临时表; + +-- 批量插入(SQL Server 2008+) +INSERT INTO 表 (id,name) VALUES +(1,'a'),(2,'b'),(3,'c'); + +-- 更新 +UPDATE 表 SET 列1=值 WHERE 条件; + +-- 删除 +DELETE FROM 表 WHERE 条件; +TRUNCATE TABLE 表; -- 更快,清空表(不记录日志) + +-- MERGE(upsert神器) +MERGE INTO 目标表 t +USING 来源表 s +ON t.id = s.id +WHEN MATCHED THEN UPDATE SET ... +WHEN NOT MATCHED THEN INSERT ... +WHEN NOT MATCHED BY SOURCE THEN DELETE; +``` + +### 5. DDL - 表结构操作 + +```sql +-- 创建表 +CREATE TABLE 表名 ( + id INT IDENTITY(1,1) PRIMARY KEY, + 名称 NVARCHAR(100) NOT NULL, + 创建时间 DATETIME DEFAULT GETDATE(), + 状态 TINYINT DEFAULT 1 +); + +-- 添加列、修改列 +ALTER TABLE 表 ADD 新列 NVARCHAR(50); +ALTER TABLE 表 ALTER COLUMN 列 NVARCHAR(200) NULL; + +-- 索引 +CREATE INDEX idx_名称 ON 表(列1,列2); +CREATE UNIQUE INDEX ... +CREATE NONCLUSTERED INDEX ... INCLUDE (列) -- 覆盖索引 + +-- 主键、外键、约束 +ALTER TABLE 表 ADD CONSTRAINT PK_表 PRIMARY KEY (id); +ALTER TABLE 表 ADD CONSTRAINT FK_表_其他表 FOREIGN KEY (id) REFERENCES 其他表(id); +``` + +### 6. 常用函数 + +**字符串**: +- `CONCAT()`, `LEFT()`, `RIGHT()`, `SUBSTRING()`, `REPLACE()`, `CHARINDEX()` +- `LEN()`, `TRIM()`, `UPPER()`, `LOWER()` + +**日期**: +- `GETDATE()`, `SYSDATETIME()` +- `DATEADD(day, 7, GETDATE())` +- `DATEDIFF(day, '2025-01-01', GETDATE())` +- `FORMAT(日期, 'yyyy-MM-dd')` +- `EOMONTH(GETDATE())` -- 月末 + +**类型转换**: +- `CAST(列 AS NVARCHAR(50))` +- `TRY_CAST()`, `TRY_CONVERT()`(安全转换) + +**NULL处理**: +- `ISNULL(列, 默认值)` +- `COALESCE(列1, 列2, 列3)` + +### 7. 事务与错误处理 + +```sql +BEGIN TRANSACTION; +BEGIN TRY + -- 操作 + COMMIT; +END TRY +BEGIN CATCH + ROLLBACK; + SELECT ERROR_MESSAGE(), ERROR_NUMBER(); +END CATCH +``` + +### 8. 临时表与表变量 + +```sql +-- 表变量(内存,适合小数据) +DECLARE @t TABLE (id INT, name NVARCHAR(50)); + +-- 临时表(物理,适合大数据,可建索引) +CREATE TABLE #temp (...); +``` + +### 9. 常用系统视图/函数 + +- `sys.tables`, `sys.columns`, `sys.indexes` +- `OBJECT_ID('表名')` +- `DBCC CHECKIDENT('表名', RESEED, 0)` -- 重置自增 +- `sp_help '表名'` -- 查看表结构 +- `sp_spaceused` -- 空间使用 + +### 推荐学习顺序 +1. SELECT + WHERE + JOIN + GROUP BY +2. 窗口函数(ROW_NUMBER、SUM OVER) +3. MERGE + 事务 +4. 索引优化 + 执行计划(Ctrl+M) diff --git a/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server常见函数分类总结.md b/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server常见函数分类总结.md new file mode 100644 index 0000000..149d562 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server常见函数分类总结.md @@ -0,0 +1,71 @@ + +## 1. 聚合函数 +| 函数 | 说明 | +|------|------| +| `COUNT()` | 统计行数 | +| `SUM()` | 求和 | +| `AVG()` | 求平均值 | +| `MIN()` / `MAX()` | 最小/最大值 | +| `STRING_AGG()` | 字符串拼接(SQL 2017+) | + +## 2. 字符串函数 +| 函数 | 说明 | +|------|------| +| `LEN()` | 返回字符串长度 | +| `CHARINDEX()` | 查找子串位置 | +| `SUBSTRING()` | 截取子串 | +| `LEFT()` / `RIGHT()` | 从左/右截取 | +| `REPLACE()` | 替换字符串 | +| `UPPER()` / `LOWER()` | 大小写转换 | +| `TRIM()` / `LTRIM()` / `RTRIM()` | 去除空格 | +| `REVERSE()` | 反转字符串 | +| `CONCAT()` | 拼接字符串(NULL 安全) | +| `FORMAT()` | 格式化字符串/日期 | + +## 3. 日期函数 +| 函数 | 说明 | +|------|------| +| `GETDATE()` | 当前系统时间 | +| `SYSDATETIME()` | 更高精度的当前时间 | +| `DATEADD()` | 日期加减 | +| `DATEDIFF()` | 计算日期差 | +| `DATEPART()` | 提取年/月/日/小时等 | +| `YEAR()` / `MONTH()` / `DAY()` | 提取年份/月份/日 | +| `EOMONTH()` | 当月最后一天 | +| `ISDATE()` | 检查是否为有效日期 | + +## 4. 数学函数 +| 函数 | 说明 | +|------|------| +| `ABS()` | 绝对值 | +| `CEILING()` / `FLOOR()` | 向上/向下取整 | +| `ROUND()` | 四舍五入 | +| `POWER()` | 幂运算 | +| `SQRT()` | 平方根 | +| `RAND()` | 随机数 | + +## 5. 类型转换 / 判空 +| 函数 | 说明 | +|------|------| +| `CAST()` | 类型转换 | +| `CONVERT()` | 类型转换(支持样式参数) | +| `ISNULL()` | 替代 NULL | +| `COALESCE()` | 返回第一个非 NULL 值 | +| `NULLIF()` | 两个值相等则返回 NULL | + +## 6. 窗口函数 +| 函数 | 说明 | +|------|------| +| `ROW_NUMBER()` | 行号 | +| `RANK()` / `DENSE_RANK()` | 排名 | +| `NTILE()` | 分桶 | +| `LAG()` / `LEAD()` | 访问前/后行数据 | +| `FIRST_VALUE()` / `LAST_VALUE()` | 分区首/末值 | + +## 7. 逻辑函数 +| 函数 | 说明 | +|------|------| +| `IIF()` | 简单条件判断(SQL 2012+) | +| `CHOOSE()` | 从列表中选值 | +| `CASE` | 多条件分支(表达式,不是函数但常用) | + diff --git a/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server的视图是什么.md b/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server的视图是什么.md new file mode 100644 index 0000000..026542e --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server的视图是什么.md @@ -0,0 +1,39 @@ +视图(View)是一个**虚拟表**,本质是**存储起来的 SELECT 查询语句**。 + +### 核心特点 + +- **不存数据**:视图本身不保存数据,数据仍然在原始表中。每次查询视图时,SQL Server 会去执行它背后的 SELECT 语句。 +- **像一个"窗口"**:你查视图就像查普通表一样,但它展示的是经过筛选、转换后的数据。 + +### 举个例子 + +```sql +-- 创建一个视图:只显示价格大于100的商品 +CREATE VIEW v_expensive_goods AS +SELECT id, name, price +FROM sh_goods +WHERE price > 100; +``` + +之后查询: +```sql +SELECT * FROM v_expensive_goods; +``` +等价于直接执行视图里的 SELECT 语句。 + +### 为什么用视图? + +| 场景 | 好处 | +|------|------| +| **简化复杂查询** | 把一堆多表 JOIN + 聚合的 SQL 存成视图,业务方直接 `SELECT * FROM v_xxx` 即可 | +| **安全性** | 只暴露部分字段(如隐藏密码、敏感列),用户只能查视图,不能直接查基表 | +| **数据隔离** | 给不同角色开不同的视图,看到的数据范围不同 | +| **屏蔽表结构变更** | 基表改字段名,视图层用别名兜住,上游查询不受影响 | + +### 注意事项 + +- **性能问题**:嵌套多层视图或视图里挂复杂查询,查起来可能慢(因为每次都是真实执行底层 SQL)。 +- **局限性**:大多数视图是只读的(不能 `INSERT`/`UPDATE`/`DELETE`),除非是"可更新视图"(简单到 SQL Server 能反向推导出对应基表的修改)。 +- **索引视图**:SQL Server 支持为视图建索引(物化视图),将查询结果实际存储下来,大幅提升频繁使用的复杂查询的性能——但这会占用存储空间,且基表更新时索引也会同步更新。 + +简单总结:**视图就是查起来像表、但本质是 SQL 脚本的一种封装工具。** diff --git a/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server联表查询类型.md b/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server联表查询类型.md new file mode 100644 index 0000000..a6c366d --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/SQL-Server/SQL-Server联表查询类型.md @@ -0,0 +1,78 @@ + +--- + +## 一、INNER JOIN(内连接) + +```sql +SELECT * FROM A INNER JOIN B ON A.id = B.a_id; +``` + +- **只返回两边都匹配到的数据** +- 表 A 的某行在表 B 找不到对应 → 不出现 +- 表 B 的某行在表 A 找不到对应 → 不出现 +- **最常用,取交集** + +--- + +## 二、OUTER JOIN(外连接)— 3 种 + +### 1. LEFT JOIN(左外连接) +```sql +SELECT * FROM A LEFT JOIN B ON A.id = B.a_id; +``` +- 返回 **左表全部行** + 右表匹配的行 +- 右表没匹配到 → 用 `NULL` 填充 + +### 2. RIGHT JOIN(右外连接) +```sql +SELECT * FROM A RIGHT JOIN B ON A.id = B.a_id; +``` +- 返回 **右表全部行** + 左表匹配的行 +- 左表没匹配到 → 用 `NULL` 填充 +- 实际用得少,习惯上把主表放左边用 LEFT JOIN + +### 3. FULL OUTER JOIN(全外连接) +```sql +SELECT * FROM A FULL OUTER JOIN B ON A.id = B.a_id; +``` +- 返回 **两边全部行**,各自没匹配到的用 `NULL` 填充 +- 相当于 LEFT JOIN + RIGHT JOIN 的并集 + +--- + +## 三、CROSS JOIN(交叉连接) + +```sql +SELECT * FROM A CROSS JOIN B; +-- 等价于 +SELECT * FROM A, B; +``` +- **笛卡尔积**:A 表每行 × B 表每行 +- 没有 ON 条件 +- A 有 m 行、B 有 n 行,结果有 m × n 行 +- **很少直接用**,但某些场景(如生成日期维度表、测试数据)会用 + +--- + +## 四、SELF JOIN(自连接) + +```sql +SELECT e1.name AS employee, e2.name AS manager +FROM emp e1 LEFT JOIN emp e2 ON e1.manager_id = e2.id; +``` +- **同一张表自己跟自己连** +- 必须用**别名**区分两份角色 +- 典型场景:员工表查上下级、分类表查父子关系 + +--- + +## 五、一张图总结区别 + +| JOIN 类型 | 左表 | 右表 | +|-----------|------|------| +| INNER JOIN | ✅ 匹配到的 | ✅ 匹配到的 | +| LEFT JOIN | ✅ **全部** | ✅ 匹配到的 | +| RIGHT JOIN | ✅ 匹配到的 | ✅ **全部** | +| FULL OUTER JOIN | ✅ **全部** | ✅ **全部** | +| CROSS JOIN | ✅ **全部**(每行 × 每行) | ✅ **全部** | +| SELF JOIN | 同一张表,用别名分饰两角 | diff --git a/mengyanote-backend/data/mengyanote/数据库/SQL定义.md b/mengyanote-backend/data/mengyanote/数据库/SQL定义.md new file mode 100644 index 0000000..6d4f822 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/数据库/SQL定义.md @@ -0,0 +1,28 @@ +SQL(Structured Query Language,结构化查询语言)是用于管理和操作关系型数据库的标准语言。 + +核心功能分为几类: + +**DDL(数据定义语言)** — 建表、改结构 +```sql +CREATE TABLE ... +ALTER TABLE ... +DROP TABLE ... +``` + +**DML(数据操作语言)** — 增删改 +```sql +INSERT ... +UPDATE ... +DELETE ... +``` + +**DQL(数据查询语言)** — 查数据 +```sql +SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... +``` + +**DCL(数据控制语言)** — 权限 +```sql +GRANT ... REVOKE ... +``` + diff --git a/mengyanote-backend/data/mengyanote/数据库/小萌芽开发中间件信息.md b/mengyanote-backend/data/mengyanote/数据库/小萌芽开发中间件信息.md index 436ebe0..1f60581 100644 --- a/mengyanote-backend/data/mengyanote/数据库/小萌芽开发中间件信息.md +++ b/mengyanote-backend/data/mengyanote/数据库/小萌芽开发中间件信息.md @@ -1,213 +1,142 @@ ## 1. Redis - ### 本机连接 - - Host: `127.0.0.1` - Port: `6379` - Password: `tyh@19900420` - 命令行: - ```bash redis-cli -h 127.0.0.1 -p 6379 -a 'tyh@19900420' ``` - ### 内网其他主机连接 - - Host: `192.168.1.100` 或 `10.1.1.100` - Port: `6379` - Password: `tyh@19900420` - 命令行: - ```bash redis-cli -h 192.168.1.100 -p 6379 -a 'tyh@19900420' ``` - ## 2. MongoDB - ### 本机连接 - - Host: `127.0.0.1` - Port: `27017` - Username: `root` - Password: `tyh@19900420` - Auth DB: `admin` - 命令行: - ```bash mongosh 'mongodb://root:tyh%4019900420@127.0.0.1:27017/admin?authSource=admin' ``` - 标准连接串: - ```text mongodb://root:tyh%4019900420@127.0.0.1:27017/admin?authSource=admin ``` - 说明: - - 密码中的 `@` 需要做 URL 编码,写成 `%40` - ### 内网其他主机连接 - - Host: `192.168.1.100` 或 `10.1.1.100` - Port: `27017` - Username: `root` - Password: `tyh@19900420` - Auth DB: `admin` - 命令行: - ```bash mongosh 'mongodb://root:tyh%4019900420@192.168.1.100:27017/admin?authSource=admin' ``` - 标准连接串: - ```text mongodb://root:tyh%4019900420@192.168.1.100:27017/admin?authSource=admin ``` - ## 3. MySQL - ### 本机连接 - - Host: `127.0.0.1` - Port: `3306` - Username: `root` - Password: `tyh@19900420` - 命令行: - ```bash mysql -h 127.0.0.1 -P 3306 -uroot -p'tyh@19900420' ``` - JDBC: - ```text jdbc:mysql://127.0.0.1:3306/?user=root&password=tyh@19900420 ``` - ### 内网其他主机连接 - - Host: `192.168.1.100` 或 `10.1.1.100` - Port: `3306` - Username: `root` - Password: `tyh@19900420` - 命令行: - ```bash mysql -h 192.168.1.100 -P 3306 -uroot -p'tyh@19900420' ``` - JDBC: - ```text jdbc:mysql://192.168.1.100:3306/?user=root&password=tyh@19900420 ``` - ## 4. PostgreSQL - ### 本机连接 - - Host: `127.0.0.1` - Port: `5432` - Username: `postgres` - Password: `tyh@19900420` - Database: `postgres` - 命令行: - ```bash PGPASSWORD='tyh@19900420' psql -h 127.0.0.1 -p 5432 -U postgres -d postgres ``` - 连接串: - ```text postgresql://postgres:tyh@19900420@127.0.0.1:5432/postgres ``` - ### 内网其他主机连接 - - Host: `192.168.1.100` 或 `10.1.1.100` - Port: `5432` - Username: `postgres` - Password: `tyh@19900420` - Database: `postgres` - 命令行: - ```bash PGPASSWORD='tyh@19900420' psql -h 192.168.1.100 -p 5432 -U postgres -d postgres ``` - 连接串: - ```text postgresql://postgres:tyh@19900420@192.168.1.100:5432/postgres ``` - ## 5. RabbitMQ - RabbitMQ 分为两类连接: - - AMQP 服务端口:`5672` - 管理后台端口:`15672` - ### 本机连接 - 推荐账号: - - Username: `admin` - Password: `shumengya520` - 备用本机账号: - - Username: `guest` - Password: `guest` - AMQP 连接串: - ```text amqp://admin:shumengya520@127.0.0.1:5672/ ``` - 管理后台: - ```text http://127.0.0.1:15672 ``` - ### 内网其他主机连接 - 推荐账号: - - Username: `admin` - Password: `shumengya520` - AMQP 连接串: - ```text amqp://admin:shumengya520@192.168.1.100:5672/ ``` - 管理后台: - ```text http://192.168.1.100:15672 ``` - 说明: - - `guest/guest` 当前仅允许从本机访问,不可用于内网其他主机远程登录 - 内网其他主机请使用 `admin/shumengya520` - ## 6. 快速汇总表 | 中间件 | 本机地址 | 内网地址 | 账号 | 密码 | 备注 | diff --git a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/AI账号/Grok账号.md b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/AI账号/Grok账号.md index 85fbc35..a8a90fc 100644 --- a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/AI账号/Grok账号.md +++ b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/AI账号/Grok账号.md @@ -1,4 +1,28 @@ shumengya666@gmail.com shumengya666@outlook.com +shumengya520 + +shumengya666@hotmail.com +shumengya520 + +shumengya888@outlook.com +shumengya520 + +shumengya233@outlook.com +shumengya520 + +adwad@shumengya.top +shumengya520 + +awdaw@shumengya.top +shumengya520 + +awda@shumengya.top +shumengya520 + +666@shumengya.top +shumengya520 + +sadwawd@shumengya.top shumengya520 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/AI账号/英伟达账号.md b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/AI账号/英伟达账号.md new file mode 100644 index 0000000..cf271ea --- /dev/null +++ b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/AI账号/英伟达账号.md @@ -0,0 +1,14 @@ +mail@smyhub.com +shumengya520 +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 + +shumengya666@gmail.com +shumengya520 +19161268223 +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 + +temp@smyhub.com +shumengya520 +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 +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 + diff --git a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/CloudFlare账号.md b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/CloudFlare账号.md index e0a2d88..9fa86e5 100644 --- a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/CloudFlare账号.md +++ b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/CloudFlare账号.md @@ -1,8 +1,17 @@ shumengya666@gmail.com smy@5201314 +shumengya +--- 3205788256@qq.com +tyh@19900420 +smyhub + +--- +1666731831@qq.com +Lcxm1234. +lcxm + +mail@smyhub.com smy@5201314 - - -Lcxm1234. \ No newline at end of file +bigmengya diff --git a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/Github账号.md b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/Github账号.md index 7094117..4b4f76e 100644 --- a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/Github账号.md +++ b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/Github账号.md @@ -1,5 +1,28 @@ 3205788256@qq.com Smy@5201314 +shumengya +--- 1666731831@qq.com -Lcxm1234. \ No newline at end of file +Lcxm1234. +lcxmlab + +--- +2143323382@qq.com +tyh@19900420 +bigmengya + +--- +3556608700@qq.com +temp@smyhub.com +9?_VytR?9rhcNC1+ + +--- +2804775686@qq.com +6@rYWcaQB@Q:H?}U +smallmengya + +--- +temp@smyhub.com +tw520smy +smy520tw diff --git a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/Grok账号.md b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/Grok账号.md deleted file mode 100644 index 0fb4773..0000000 --- a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/Grok账号.md +++ /dev/null @@ -1,4 +0,0 @@ -shumengya666@gmail.com - -shumengya666@hotmail.com -shumengya520 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/邮箱账号/Gmail邮箱.md b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/邮箱账号/Gmail邮箱.md index 5a95fbe..ac8f2ae 100644 --- a/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/邮箱账号/Gmail邮箱.md +++ b/mengyanote-backend/data/mengyanote/树萌芽の小本本/账号合集/邮箱账号/Gmail邮箱.md @@ -15,4 +15,5 @@ xfst qxwn mynh xujg NathysYemaya892@gmail.com hgwrdyhuvt7 tanskielsmoreut891@googlemail.com -https://2fa.live/tok/yxbt267ttjvappfxsvfna2bsj4grjph3 \ No newline at end of file +https://2fa.live/tok/yxbt267ttjvappfxsvfna2bsj4grjph3 +--- diff --git a/mengyanote-backend/data/mengyanote/树萌芽の小本本/重要信息记录.md b/mengyanote-backend/data/mengyanote/树萌芽の小本本/重要信息记录.md index 6e03ffc..0d56853 100644 --- a/mengyanote-backend/data/mengyanote/树萌芽の小本本/重要信息记录.md +++ b/mengyanote-backend/data/mengyanote/树萌芽の小本本/重要信息记录.md @@ -76,3 +76,7 @@ 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 成都市青羊区光华大道一段57号4栋 **唐洪一家:** 绵阳市涪城区 + +杨轩PTA +19381126615 +123456789 diff --git a/mengyanote-backend/data/mengyanote/生活科普/租房全流程避坑终极指南.md b/mengyanote-backend/data/mengyanote/生活科普/租房全流程避坑终极指南.md new file mode 100644 index 0000000..f6cd00f --- /dev/null +++ b/mengyanote-backend/data/mengyanote/生活科普/租房全流程避坑终极指南.md @@ -0,0 +1,129 @@ + +## 一、找房渠道与前期筹备 + +1. 找房渠道参考:贝壳找房、抖音、微信本地租房号、链家、安居客、闲鱼、豆瓣租房小组、wellcee + +>`个人`:用过贝壳找房、自如、链家、“小绿书”、微信。在这个中介充满全世界的时代,想要租到一个好房可太难了,要花大量的去筛选信息,最后发现,还是中介对接的你 :skull_and_crossbones:。我自己最开始用的是自如,自如的话,就是贵,然后服务的话,有公共区域打扫,变相的出了这部分服务费...贝壳找房的话,我是用它的地图找房来进行最初的筛选,看下整体的价格,链家也是如此 +![微信图片\_20260517101117\_78\_212|214x500](https://cdn3.ldstatic.com/original/4X/2/6/4/2640d5caeb1e84585548dbaa1f05366f7d442d29.jpeg) +然后我会找到对应的区域,骑个单车去转转,然后去线下的链家、贝壳等,找他们中介聊聊,进一步了解一下走中介的一个价格,如果觉得合适,可以直接去看房和签约,去线下转的时候,可以注意一些小区的墙上、电线杆子上面、信息展示板上面,有些可能会有一些房东直租的信息,也可以找下小区周围的大爷、大妈咨询一下,他们最是清楚了。然后就是所在的城市,是否有政府牵头的平台,成都的话,住建局有一个[平台](https://zw.cdzjryb.com/cucenter_dist/#/), +![图片|690x399](https://cdn3.ldstatic.com/original/4X/2/7/5/275b301032d591415e6b0d6ca7cd06d687e373b4.png) +这个平台上面,可以去申请公租房、包租房(好的地段特别难抢,我现在就是租的包租房,还是有点一言难尽...)、核验房源...具体可以自己去看[成都住房租赁平台](https://zw.cdzjryb.com/rent/#/main/index),这上面最实用的功能就是房源核验以及租房模块的个人房源,这里比较容易蹲到房东直租... +![图片|690x376](https://cdn3.ldstatic.com/original/4X/d/7/c/d7cafc594efef869234b1dad75028b7fc43744ac.jpeg) +如果没有蹲到,那就是后面的方案了,一个是在抖音上面,找一些有一定粉丝量的中介,没错中介 :eyes:,或者就是在微信搜索你所在的地区+租房,大概率会找到一些公众号或者小程序, +![1a4eb0f0541af0a7ab3c6a04f75e67e3|214x500](https://cdn3.ldstatic.com/original/4X/5/a/7/5a73c137a6624801af6d2a5a68d4c662e7a6389c.jpeg) +![f3a5f116a74ed5e1dbc99cf3313a8d59|214x500](https://cdn3.ldstatic.com/original/4X/4/6/4/4640125ac0c3ff5c29718de1563f7dd6c6b711ad.jpeg) +抖音上面找的中介,没什么好说的,货比三家。微信找的租房群,里面的信息就要自己分辨了,有房东、有中介、有转租的、有招合租的,里面还是蹲到好房的。 + + + + + + +1. 前期核心定项:提前明确目标地段、厨房条件、户型(几室几厅)、租金预算(沟通时可往低压),提前明确是否接受中介费、看房费,筛选房源时优先标注无中介费的个人直租 / 房东直签房源 +> 租房的时候,最好对你要租的地区的租房市场有个大致了解,特别是对于你要租的户型来说,特别重要,可以避免后续踩坑。就拿套一来说,不要相信抖音或者小绿书以及一些租房平台,配的特别精致的图片和超低的价格,这种里面的水可太深了,要嘛就是看的和图片不一致,要嘛就是位置不对,要嘛就是隔出来的房间,要嘛就是串串房等等,你玩不过的,就像我前面说的,去一些大的平台看下价格,再到线下去跑一趟,大致心里有个数,羊毛出在羊身上,不要被宰了。 +3. 比价技巧:可同时找两个中介双线带看,同片区同类型房源对比价格、配套与房屋状况,避免溢价 + +## 二、实地看房全维度逐项核验 + +### 2.1 楼层与户型基础避坑 + +- 优先规避一楼(临街 / 小区内噪音大、隐私性差)、顶楼(普遍存在冬冷夏热、屋面漏水风险)户型 +- 确认房屋朝向、每日采光时长、通风效果,有无返潮、霉味、异味问题,是否带阳台 +- 提前实地踏勘房屋周边,确认小区安保、门禁规范度,以及周边超市、快递驿站、地铁 / 公交站等生活配套的便利度,排查周边有无噪音源、污染源 +> 那这里,如果你前面已经按条件筛选了或者已经去线下转了一圈的话,心里大概有数了,要是没有去看的话,建议在实地看房的时候,在约好的时间,提前一两个小时,去你小区附近看一看具体的生活配套设施:有没有菜市场、快递柜在什么地方、有没有公园、有没有健身房等等,按照你自己的需求去大致看一下。特别是像我这种睡眠浅的,最好提前去蹲个点,或者去问下小区里面的大爷大妈或者去菜市场问问,晚上吵不吵,不然你租完房就是纯受罪。 + +### 2.2 全屋硬件与设施逐项试机核验(必做) + +- 水路系统:测试马桶冲水水压、地漏排水速度、花洒出水效果、洗手池 / 厨房水槽是否漏水、下水道有无堵塞 / 反味,确认水管、热水器有无漏水、日常用水水压是否稳定 +- 电路与电器:逐个测试全屋灯具、开关、插座能否正常使用;开机测试空调制冷 / 制热、抽油烟机、冰箱制冷、洗衣机等所有家电功能是否正常,有无异响、故障 +- 硬装与家具:检查墙面有无脱皮、发霉、渗水、开裂,地板有无起翘、空鼓,门窗密封性、开关是否顺畅;清点全屋所有家具,逐项试用,确认床架、衣柜、沙发等大件家具有无破损、发霉、结构不稳 +- 基础配套:测试全屋手机网络信号、wifi 覆盖效果,确认房屋能否拉网线、可接入的通讯运营商范围 +>这里呢,如果你租的是老小区或者说装修时间有点的久了,就更要注意了,看房的时候,最好是当着房东(中介、代理人...)的面,去动一动、拉一拉、扯一扯...举个自身例子,一般洗衣机的入水口,有一根入水管会和水龙头连接,而那个水龙头和入水管接口连接那玩意儿,叫洗衣机水嘴,这玩意儿会随着时间,不断被水锈蚀,静待一个有缘人,一个特殊的日子,要嘛就是你洗衣服的时候,突然断开喷你一身水,要嘛就是你没在家,来一个“水漫金山”...最好动手去扯一下,转一下看有没有漏水以及老化程度,其它也是一样,等待命中注定的你 + +### 2.3 居住体验核心核验 + +- 隔音效果:测试墙体、门窗隔音,确认早 8 点、晚 11 点两个核心时段的室内噪音情况 +- 隐私安全:用红外探测器全面排查全屋针孔摄像头,重点检查插座、洞孔、洗手台、卫生间、卧室、烟雾报警器等隐蔽位置 +- 居住稳定性:提前询问小区 / 楼栋是否会频繁停水停电,提前规避高风险房源 +> 隔音效果,如果特别敏感的人,可以准备一个蓝牙音响或者带个平板,只要够响的玩意儿就行,在房间里播放,然后关门在外面听一下。 +隐私安全这里,红外探测器现在还靠不靠谱,我没试过,大老爷们儿也就无所谓了,女孩子还是注意下,(男孩子也要保护好自己 :eyes:),可以去全国最大的大学--B站上面去搜索一些相关的内容,小绿书的话,注意辨别里面的信息,有一个自己的判断! + +### 2.4 权责与规则提前沟通 + +- 维修责任:提前明确大件家具、家电、硬装自然损坏的维修责任方,所有约定拒绝口头承诺,必须写入合同 +- 改造权限:确认能否在屋内挂钩、贴墙纸、墙面打洞、换锁等改造行为,明确允许的范围 +- 特殊约定:提前确认租赁期内,若房东出售房屋,对应的租赁合同履约规则、租客安置方案、违约赔偿标准,全部写入合同 +- + +> 呐,这里就开始涉及到钱以及纠纷了,不要去相信别人口头说的这个房东怎么怎么好,不会的,你放心这些话,涉及到未来可能产生纠纷的事项,最好都提前写进合同里面,可以预防后续的一些扯皮。 + +## 三、全费用明细确认(写入合同,杜绝隐性收费) + + +### 3.1 核心缴费项与标准 + +- 房租与押金:明确租金金额、支付方式(月付 / 季付 / 年付)、押几付几,空房户型普遍可协商押一付一 +- 中介费 / 看房费:提前明确是否需要缴纳、缴纳比例、缴纳时间,拒绝未看房先收费的要求 +- 水电费:明确是民用还是商用标准,参考基准:**民用水 6 元 / 吨、电 0.5-0.8 元 / 度;商用水 9 元 / 吨、电 1.1 元 / 度**;确认是否为独立户表,能否自行向官方缴纳,还是需交由房东代缴,明确水表、电表的安装位置 +- 其他固定费用:确认燃气服务费、物业费、网费、公摊费、卫生费等所有其他费用的金额、缴纳方式、承担方,索要物业官方联系方式,可致电物业核实物业费是否存在欠缴情况 + +> 这里提一嘴: +中介费,成都这边,大部分是房东和租客一人出一半,但是有的房东不想出,这个你要和中介明确。 +水电气费,确认是否为独立户表,能否向官方缴纳,这里注意,向官方缴纳的意思就是,你能在微信或者支付宝等大众软件的便民生活模块(各个软件都差不多),或者直接搜电费缴纳等,能够在上面通过户号绑定你所租的房子,并且能够查询到对应的使用情况和进行缴费。这里防止的是,如果你的水电气费是直接给房东或者代理人代缴的话,你是不知道对应的使用和收费情况的,别人说是多少就是多少,日积月累,还是一笔不小的开支。 + +### 3.2 退租扣费提前明确 + +- 提前约定退租时,是否会扣除卫生费、电器损耗费、门卡 / 门锁工本费等费用,明确各项扣费的标准、依据,无约定的扣费项退租时有权拒绝 +- 明确租赁期内,水费、电费、网费、维修费、家电损耗费的承担方,避免后续纠纷 + +## 四、合同签约核心规范与必备条款(零踩雷核心) + +> 写在前面,合同特别重要!合同特别重要!合同特别重要!如果你是通过中介,走的平台签订的合同,大的问题应该不会有,不过也需要将合同事项核对清楚。如果是通过房东直签的合同,那你就要仔细核对合同明细了,不少合同都会存在一些霸王条款以及摘出主体责任等等,要小心,不然吃亏的就是自己了。 +可以在你所在的城市的住建局网站,搜索租赁合同,大概率会搜到官方提供的模板合同。当然,上面提到的成都住建局的网站就有一版合同模板,可以进行参考。 + +### 4.1 签约主体与证件核验(缺一不可) + +- 签约必须三方到场:租客本人、中介 / 代理方、房东本人,最终合同需房东亲笔签名;若为代理公司签约,必须确认公司正规资质,明确房东房屋钥匙的唯一归属人,避免一房多租 +- 房东资质核验:必须出示房屋不动产权证(房产证)、房东本人身份证原件,核对证件与产权人信息完全一致后,拍照留存;若为二房东签约,需额外提供:大房东身份证复印件、大房东出具的**书面委托转租授权书**、大房东与二房东的原始租赁合同,确认剩余租期完全覆盖你的租赁周期 +- 租客证件规范:本人身份证复印件,必须在显眼位置标注「仅供本次租房使用」,避免证件被滥用 + +### 4.2 合同必须写入的核心条款(一项都不能少) + +1. 基础信息:明确合同租期起止时间、房屋详细坐落地址(精确到市 / 区 / 街道 / 楼栋门牌号) +2. 费用规则:明确租金、押金的金额、支付时间、支付方式;所有费用的缴纳时间、金额、承担方 +4. 表具底数:抄录合同签订当日,水表、电表、燃气表的最终数值,拍照留存,明确上个租户已结清所有欠费,与本次租客无关 +5. 维修责任:明确租赁期内,家电、家具、硬装的自然损坏 / 人为损坏,对应的维修、赔偿责任方(参考《民法典》第 712 条:出租人应当履行租赁物的维修义务) +6. 违约责任:明确双方违约的处理方式与赔付标准,包括房东提前收房、租客提前退租、房东卖房违约等情况的违约金、费用结算规则 +7. 补充约定:将前期沟通好的改造权限、清洁要求、家具更换、物业费承担等所有口头约定,全部补充写入合同,口头承诺无法律效力 + +### 4.3 签约留证必备动作 + +- 合同附带《房屋物品清单》,详细列明全屋家具、家电、硬装的数量、品牌、成色、破损情况,三方签字确认 +- 当着房东 / 中介的面,拍摄房屋全景视频、所有瑕疵破损的照片,同步发给房东 / 中介确认,自身存档留存 + +> 拍摄留痕还是很重要的,在签合同的时候或者是看房的时候,将房屋的瑕疵拍摄下来,并且打上水印,发给代理人或者房东确认,避免后面的“提灯定损”。 + +## 五、履约与转账留证规范 + +- 所有房租、押金、中介费等款项,优先选择银行转账、支付宝 / 微信实名转账,拒绝现金交易 +- 每一笔转账都必须备注清楚款项用途、对应租期、金额,示例:「2026 年 5 月 - 2026 年 10 月房租 XX 元」「租房押金 XX 元」 +- 全程保存所有转账记录、聊天记录、合同原件、房屋照片 / 视频,直至退租交接完成、押金全额退还后 + +> 钱相关的,都留一个心眼儿。这都2026年了,如果还要求你用现金支付的话,听话,咱这个房,不租也罢,换一个嗷。 + +## 六、退房交接与押金退还规范 + +- 提前确认退租需提前多久告知房东,明确需提前几天搬走,做好交接准备 +- 退租前按合同约定完成全屋清洁,打扫后拍摄全屋照片 / 视频留存 +- 交接时当场抄录水电燃气表最终读数,结清所有应由租客承担的费用 +- 合同约定押金当场退还的,必须在房屋验收无误后,当场完成押金退还;约定延后到账的,必须明确到账时限,写入交接单 +- 交接完成后,双方签署退房交接确认单,终结租赁合同权利义务 + +> 交接确认后,就和你没关系了,你就可以把房东删了,不管他后来说什么,一律不用管了。如果再给你打电话骚扰的话,直接报J,不用墨迹。 + + +## 七、维权渠道与应急方式 + +- 租房税务、乱收费相关问题:拨打 12366 +- 押金纠纷、租房消费维权、中介违规问题:拨打 12315 +- 合同纠纷、二房东卷款等民事纠纷:可向辖区街道办、社区居委会申请调解,或向人民法院提起诉讼 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/2025年蓝桥杯PythonB组真题解析/1.攻击次数.md b/mengyanote-backend/data/mengyanote/算法与数据结构/2025年蓝桥杯PythonB组真题解析/1.攻击次数.md deleted file mode 100644 index dd1d22d..0000000 --- a/mengyanote-backend/data/mengyanote/算法与数据结构/2025年蓝桥杯PythonB组真题解析/1.攻击次数.md +++ /dev/null @@ -1,26 +0,0 @@ -设敌人的初始血量为 H = 2025 。 -每个回合的攻击量如下: -- 第1英雄:每回合5点 -- 第2英雄:奇数回合15点,偶数回合2点 -- 第3英雄:余数1时2点,余数2时10点,余数0时7点 - -计算每3个回合的总攻击量: -- 第1回合: 5 + 15 + 2 = 22 点 -- 第2回合: 5 + 2 + 10 = 17 点 -- 第3回合: 5 + 15 + 7 = 27 点 -- 总和: 22 + 17 + 27 = 66 点 - -完整3个回合的次数: - leftlfloor frac{2025}{66} rightrfloor = 30 -剩余血量: - 2025 - 30 times 66 = 45 - -剩余45点血量需3个回合: -- 第1回合: 45 - 22 = 23 -- 第2回合: 23 - 17 = 6 -- 第3回合: 6 - 27 = -21 (游戏结束) - -总回合数: - 30 times 3 + 3 = 93 - -答案: boxed{93} \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/1.两数之和.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(1)1.两数之和.md similarity index 99% rename from mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/1.两数之和.md rename to mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(1)1.两数之和.md index ca897e4..d062404 100644 --- a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/1.两数之和.md +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(1)1.两数之和.md @@ -3,7 +3,7 @@ - **输入**:一个整数数组 `nums` 和一个整数目标值 `target`。 - **输出**:两个整数的下标,这两个下标对应的数组元素之和等于 `target`。 -- **约束条件**: +- **约束条件**: - 数组长度至少为 2。 - 数组中每个数和目标值的范围很大(-10⁹ 到 10⁹),但 Python 的 int 可以处理。 - **保证有且只有一对下标满足条件**,且不能重复使用同一个元素(即两个下标必须不同)。 diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(10)560. 和为 K 的子数组.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(10)560. 和为 K 的子数组.md new file mode 100644 index 0000000..a1ea756 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(10)560. 和为 K 的子数组.md @@ -0,0 +1,180 @@ +**标签**:数组、哈希表、前缀和、子数组 + +# 和为 K 的子数组 + +## 题目理解 +- **输入**:一个整数数组 `nums`(长度 1 到 2×10⁴)和一个整数 `k`(范围 -10⁷ 到 10⁷)。数组元素范围 -1000 到 1000。 +- **输出**:一个整数,表示有多少个**连续非空子数组**的和等于 `k`。 +- **关键点**:子数组必须是连续的,不能跳过元素。元素可以是负数。 +- **具体例子**: + - `nums = [1,1,1], k = 2` → 子数组 `[1,1]`(下标 0-1)和 `[1,1]`(下标 1-2),共 2 个。 + - `nums = [1,2,3], k = 3` → 子数组 `[1,2]`(和=3)和 `[3]`(和=3),共 2 个。 + - `nums = [1,-1,0], k = 0` → 子数组 `[1,-1]`、`[0]`、`[1,-1,0]`,共 3 个。 + +--- +## 解法一:暴力枚举(理解用) +> 原则:最直观的方法,枚举所有可能的子数组,计算每个子数组的和。 + +### 思路 +1. **为什么想到这种方法**:子数组 = 连续的一段。要找出所有和为 k 的子数组,最直接的想法就是枚举所有可能的起点和终点,计算区间和。 +2. **步骤分解**: + - 用两层循环:外层循环 i 表示子数组的起点,内层循环 j 从 i 到末尾表示终点。 + - 对于每个起点 i,维护一个累加和 `current_sum`,每次加上 `nums[j]` 得到子数组 `[i..j]` 的和。 + - 如果 `current_sum == k`,计数器加 1。 +3. **注意**:这种方法虽然直观,但时间复杂度是 O(n²),n=2×10⁴ 时约 4 亿次操作,可能会超时。 + +### 代码 +```python +class Solution: + def subarraySum(self, nums, k): + """ + 暴力枚举所有子数组 + """ + n = len(nums) + count = 0 + + # 枚举所有起点 + for i in range(n): + current_sum = 0 + # 枚举所有终点(从 i 开始到末尾) + for j in range(i, n): + current_sum += nums[j] # 累加得到子数组 i..j 的和 + if current_sum == k: + count += 1 + + return count + +# 测试 +sol = Solution() +print(sol.subarraySum([1,1,1], 2)) # 2 +print(sol.subarraySum([1,2,3], 3)) # 2 +print(sol.subarraySum([1,-1,0], 0)) # 3 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n²) | 两层循环,每个子数组的和通过累加计算 | +| 空间 | O(1) | 只用了几个变量 | + +### 边界情况 +- **k = 0**:注意空子数组不算,但单个元素 0 或正负抵消的子数组都算。 +- **数组长度为 1**:只有 1 个子数组,检查是否等于 k。 +- **数组包含负数**:子数组和可能会先增后减,枚举法仍能正确覆盖。 + +--- +## 解法二:前缀和 + 哈希表(最优解法) +> 改进点:将 O(n²) 降到 O(n),通过前缀和与哈希表避免重复计算。 + +### 思路 +1. **为什么想到这种方法**:定义前缀和 `prefix[i]` 表示从 `nums[0]` 到 `nums[i-1]` 的和(即前 i 个元素的和)。那么子数组 `[j..i-1]` 的和 = `prefix[i] - prefix[j]`。我们要找 `prefix[i] - prefix[j] == k`,即 `prefix[j] == prefix[i] - k`。所以当我们遍历到 i 时,只需要知道之前有多少个 j 使得 `prefix[j] == prefix[i] - k`。 +2. **步骤分解**: + - 使用一个哈希表(字典)`prefix_count`,键是前缀和的值,值是该前缀和出现的次数。 + - 初始化 `prefix_count = {0: 1}`,表示前缀和为 0 出现过 1 次(这样当 `prefix[i] == k` 时,`prefix[i] - k = 0` 能在哈希表中找到)。 + - 遍历数组,维护当前前缀和 `current_sum`(从 0 累加)。 + - 对于每个位置,计算 `target = current_sum - k`。如果 `target` 在哈希表中,说明存在 `target` 个前缀和,使得 `current_sum - target = k`,即找到了 `target` 个以当前位置结尾的子数组,累加到答案。 + - 将 `current_sum` 加入哈希表(次数加 1),继续下一个位置。 +3. **注意**:前缀和的定义有多种方式。这里采用 `current_sum` 表示从 0 到当前位置(包含)的和。这样子数组 `[j+1..i]` 的和 = `current_sum - prefix_sum[j]`。 + +### 代码 +```python +class Solution: + def subarraySum(self, nums, k): + """ + 前缀和 + 哈希表 + """ + # 哈希表:记录每个前缀和出现的次数 + # 初始放入 0:1,表示前缀和为 0 出现了 1 次(空数组) + prefix_count = {0: 1} + current_sum = 0 # 当前位置的前缀和(从 0 到 i 的和) + count = 0 + + for num in nums: + current_sum += num # 更新前缀和 + + # 我们需要找之前有多少个前缀和等于 current_sum - k + target = current_sum - k + if target in prefix_count: + count += prefix_count[target] # 加上这些前缀和出现的次数 + + # 将当前前缀和加入哈希表 + if current_sum in prefix_count: + prefix_count[current_sum] += 1 + else: + prefix_count[current_sum] = 1 + + return count + +# 测试 +sol = Solution() +print(sol.subarraySum([1,1,1], 2)) # 2 +print(sol.subarraySum([1,2,3], 3)) # 2 +print(sol.subarraySum([1,-1,0], 0)) # 3 +print(sol.subarraySum([1], 1)) # 1 +print(sol.subarraySum([1,2,1,2,1], 3)) # 4([1,2], [2,1], [1,2], [2,1]) +``` + +### 手动模拟(`nums = [1,1,1], k = 2`) +| 步骤 | num | current_sum | target = current_sum - k | prefix_count 之前 | 找到的次数 | 更新 prefix_count | +|------|-----|-------------|--------------------------|-------------------|-----------|-------------------| +| 初始 | - | 0 | - | {0:1} | - | - | +| i=0 | 1 | 1 | 1-2 = -1 | {0:1} | 0 | {0:1, 1:1} | +| i=1 | 1 | 2 | 2-2 = 0 | {0:1, 1:1} | 1(0出现1次)| {0:1, 1:1, 2:1} | +| i=2 | 1 | 3 | 3-2 = 1 | {0:1, 1:1, 2:1} | 1(1出现1次)| {0:1, 1:1, 2:1, 3:1} | +总计数 = 0 + 1 + 1 = 2 ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 只遍历一次数组,每次哈希表操作 O(1) | +| 空间 | O(n) | 哈希表最多存储 n+1 个不同的前缀和 | + +--- +## 解法三:前缀和 + 哈希表(另一种写法) +> 说明:用列表存储前缀和再查哈希表,本质相同,但更清晰地展示“先计算前缀和数组,再遍历”的思路。 + +### 代码 +```python +class Solution: + def subarraySum(self, nums, k): + """ + 先计算前缀和数组,再使用哈希表 + """ + n = len(nums) + # prefix[i] 表示 nums[0] 到 nums[i-1] 的和(前 i 个元素的和) + prefix = [0] * (n + 1) + for i in range(n): + prefix[i+1] = prefix[i] + nums[i] + + # 现在子数组 nums[j..i-1] 的和 = prefix[i] - prefix[j] + count = 0 + prefix_count = {} + for i in range(n + 1): + # 寻找有多少个 j < i 使得 prefix[j] == prefix[i] - k + target = prefix[i] - k + if target in prefix_count: + count += prefix_count[target] + + # 将当前前缀和加入哈希表 + if prefix[i] in prefix_count: + prefix_count[prefix[i]] += 1 + else: + prefix_count[prefix[i]] = 1 + + return count +``` + +### 复杂度分析(同解法二) + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力枚举 | O(n²) | O(1) | 思路最简单,适合小数据 | n=2×10⁴ 时会超时 | +| 解法二:前缀和+哈希表 | O(n) | O(n) | 时间最优,面试标准解法 | 需要理解前缀和与哈希表的配合 | + +**推荐场景**: +- 初学阶段:先写暴力法,理解子数组枚举过程,确认问题理解正确。 +- 面试阶段:必须用前缀和+哈希表解法。这是“子数组和问题”的经典套路,类似题目(如 974. 和可被 K 整除的子数组)都可以用这个思想。 +- 易错提醒:别忘了初始化 `{0: 1}`,它处理了从开头到当前位置的子数组和为 k 的情况(即 `prefix[i] == k` 时,`target = 0` 能在哈希表中找到)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(11)239. 滑动窗口最大值.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(11)239. 滑动窗口最大值.md new file mode 100644 index 0000000..0743280 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(11)239. 滑动窗口最大值.md @@ -0,0 +1,194 @@ +**标签**:数组、滑动窗口、单调队列、双端队列 + +# 滑动窗口最大值 + +## 题目理解 +- **输入**:一个整数数组 `nums`(长度 n,1 ≤ n ≤ 10⁵)和一个窗口大小 `k`(1 ≤ k ≤ n)。数组元素范围 -10⁴ 到 10⁴。 +- **输出**:一个数组,包含每个滑动窗口的最大值。窗口从最左侧开始,每次向右移动一位,直到窗口右端到达数组末尾。总共会有 `n - k + 1` 个窗口。 +- **核心挑战**:需要在 O(n) 时间内完成,因为 n 最大为 10⁵,O(n × k) 会超时。 +- **具体例子**: + - `nums = [1,3,-1,-3,5,3,6,7], k = 3` → 输出 `[3,3,5,5,6,7]`。 + - `nums = [1], k = 1` → 输出 `[1]`。 + +--- +## 解法一:暴力法(理解用) +> 原则:最直观的方法,对每个窗口遍历所有元素找最大值。 + +### 思路 +1. **为什么想到这种方法**:滑动窗口的概念很直观,对于每个窗口,检查窗口内的所有元素,找出最大值。 +2. **步骤分解**: + - 结果数组长度为 `n - k + 1`。 + - 对于每个窗口起始索引 `i`(从 0 到 `n-k`): + - 窗口内的元素是 `nums[i]` 到 `nums[i+k-1]`。 + - 遍历这个范围,找到最大值,加入结果数组。 + +### 代码 +```python +class Solution: + def maxSlidingWindow(self, nums, k): + """ + 暴力法:每个窗口单独找最大值 + """ + n = len(nums) + if n == 0 or k == 0: + return [] + + result = [] + # 遍历每个窗口的起始位置 + for i in range(n - k + 1): + # 在当前窗口 [i, i+k-1] 中找最大值 + window_max = nums[i] + for j in range(i + 1, i + k): + if nums[j] > window_max: + window_max = nums[j] + result.append(window_max) + + return result + +# 测试 +sol = Solution() +print(sol.maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3)) # [3,3,5,5,6,7] +print(sol.maxSlidingWindow([1], 1)) # [1] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n × k) | 有 n-k+1 个窗口,每个窗口找最大值需 O(k) | +| 空间 | O(1) | 除了输出数组外,只用了几个变量 | + +### 边界情况 +- **k = 1**:每个窗口只有一个元素,输出就是原数组。 +- **k = n**:只有一个窗口,输出数组中只有一个元素(整个数组的最大值)。 +- **数组包含负数**:暴力法依然正确。 + +--- +## 解法二:单调队列(最优解法) +> 改进点:用双端队列(deque)维护窗口内可能成为最大值的元素下标,保证队列中元素对应数值单调递减(从队首到队尾),这样队首始终是当前窗口的最大值。 + +### 思路 +1. **为什么想到这种方法**:当窗口向右移动时,我们只需要知道新加入的元素和即将移除的元素。如果能在 O(1) 时间内获得当前窗口的最大值,就能将总时间降到 O(n)。单调队列可以做到:队列中存储元素的下标,且这些下标对应的数值从队首到队尾是**递减**的。 +2. **核心规则**: + - 队列中保存的是下标,但比较时用的是 `nums[下标]`。 + - **队首**永远是当前窗口最大值的下标。 + - **加入新元素**时:从队尾开始,移除所有比新元素小的元素(因为它们在新元素存在期间永远不可能成为最大值),然后将新元素下标加入队尾。 + - **移除离开窗口的元素**时:如果队首元素的下标已经离开窗口(即 `队列[0] <= i - k`),则将其从队首弹出。 + - 每个窗口的最大值 = `nums[队列[0]]`。 +3. **步骤分解**: + - 初始化一个空的双端队列 `deque`。 + - 先处理第一个窗口(前 k 个元素): + - 遍历 i 从 0 到 k-1,将元素加入队列(遵循上述规则)。 + - 第一个窗口的最大值 = `nums[队列[0]]`,加入结果。 + - 然后遍历 i 从 k 到 n-1: + - 移除离开窗口的元素:如果队列非空且 `队列[0] == i - k`,则从队首弹出。 + - 加入新元素 `nums[i]`:从队尾移除所有小于 `nums[i]` 的元素下标,然后将 i 加入队尾。 + - 当前窗口的最大值 = `nums[队列[0]]`,加入结果。 + +### 代码 +```python +from collections import deque + +class Solution: + def maxSlidingWindow(self, nums, k): + """ + 单调队列(双端队列):队首始终是当前窗口最大值的下标 + """ + n = len(nums) + if n == 0 or k == 0: + return [] + + # 双端队列:存储元素的下标,保证对应的数值从队首到队尾单调递减 + dq = deque() + result = [] + + # 处理第一个窗口(前 k 个元素) + for i in range(k): + # 从队尾移除所有比当前元素小的元素 + # 因为当前元素更大,那些更小的元素在窗口内永远不会成为最大值 + while dq and nums[dq[-1]] < nums[i]: + dq.pop() + dq.append(i) # 加入当前元素下标 + + # 第一个窗口的最大值 + result.append(nums[dq[0]]) + + # 处理后续窗口 + for i in range(k, n): + # 1. 移除离开窗口的元素(队首下标等于 i-k 时) + if dq and dq[0] == i - k: + dq.popleft() + + # 2. 加入新元素 nums[i] + while dq and nums[dq[-1]] < nums[i]: + dq.pop() + dq.append(i) + + # 3. 当前窗口的最大值 + result.append(nums[dq[0]]) + + return result + +# 测试 +sol = Solution() +print(sol.maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3)) # [3,3,5,5,6,7] +print(sol.maxSlidingWindow([1], 1)) # [1] +print(sol.maxSlidingWindow([7,2,4], 2)) # [7,4] +``` + +### 手动模拟(`nums = [1,3,-1,-3,5,3,6,7], k = 3`) + +**初始**:dq = [] + +**第一个窗口(i=0~2)**: +- i=0: dq 空,加入 0 → dq=[0](对应数值 1) +- i=1: nums[1]=3,队尾 nums[0]=1 < 3,弹出 0;dq 空,加入 1 → dq=[1](对应 3) +- i=2: nums[2]=-1,队尾 nums[1]=3 > -1,不弹出,直接加入 2 → dq=[1,2](对应 3, -1) +窗口最大值 = nums[1] = 3,result=[3] + +**滑动到 i=3**: +- 移除离开窗口元素:窗口 [1,2,3](原窗口 [0,1,2] 移除 0),队首是 1 ≠ 0,不移除。 +- 加入 i=3,nums[3]=-3:队尾 nums[2]=-1 > -3,不弹出,加入 3 → dq=[1,2,3] +- 最大值 = nums[1]=3,result=[3,3] + +**滑动到 i=4**: +- 移除离开窗口元素:新窗口 [2,3,4],队首 1 已经离开(1 < 2),弹出队首 → dq=[2,3] +- 加入 i=4,nums[4]=5:队尾 nums[3]=-3 < 5,弹出 3;队尾 nums[2]=-1 < 5,弹出 2;dq 空,加入 4 → dq=[4] +- 最大值 = nums[4]=5,result=[3,3,5] + +**滑动到 i=5**: +- 移除离开窗口:新窗口 [3,4,5],队首 4 未离开 → 不移除 +- 加入 i=5,nums[5]=3:队尾 nums[4]=5 > 3,不弹出,加入 5 → dq=[4,5] +- 最大值 = nums[4]=5,result=[3,3,5,5] + +**滑动到 i=6**: +- 移除离开窗口:新窗口 [4,5,6],队首 4 未离开 → 不移除 +- 加入 i=6,nums[6]=6:队尾 nums[5]=3 < 6,弹出 5;队尾 nums[4]=5 < 6,弹出 4;dq 空,加入 6 → dq=[6] +- 最大值 = nums[6]=6,result=[3,3,5,5,6] + +**滑动到 i=7**: +- 移除离开窗口:新窗口 [5,6,7],队首 6 未离开 → 不移除 +- 加入 i=7,nums[7]=7:队尾 nums[6]=6 < 7,弹出 6;dq 空,加入 7 → dq=[7] +- 最大值 = nums[7]=7,result=[3,3,5,5,6,7] + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 每个元素最多入队一次、出队一次 | +| 空间 | O(k) | 双端队列最多存储 k 个元素下标 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力枚举 | O(n × k) | O(1) | 思路简单,易于实现 | k 较大时严重超时 | +| 解法二:单调队列 | O(n) | O(k) | 线性时间,面试标准解法 | 需要理解单调队列维护逻辑 | + +**推荐场景**: +- 初学阶段:写暴力法确认问题理解正确,但不要提交(n=10⁵, k=10⁵ 时会超时)。 +- 面试阶段:必须掌握单调队列解法。这是滑动窗口求最值问题的经典模板,类似题目(如 1438. 绝对差不超过限制的最长连续子数组)也可以扩展使用。 + +**易错提醒**: +- 队列中存储的是**下标**,而不是数值本身,这样可以方便判断元素是否离开窗口。 +- 当新元素加入时,要**从队尾移除所有比它小的元素**,而不是只移除一个。这样才能保证队列单调递减。 +- 移除离开窗口元素时,只检查队首下标是否等于 `i - k`(因为窗口每次只移动一步,每次最多只有一个元素离开窗口)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(12)76. 最小覆盖子串.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(12)76. 最小覆盖子串.md new file mode 100644 index 0000000..f1377e4 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(12)76. 最小覆盖子串.md @@ -0,0 +1,177 @@ +**标签**:字符串、滑动窗口、哈希表、双指针 + +# 最小覆盖子串 + +## 题目理解 +- **输入**:两个字符串 `s`(长度 m,1 ≤ m ≤ 10⁵)和 `t`(长度 n,1 ≤ n ≤ 10⁵)。字符串只包含英文字母(大小写敏感)。 +- **输出**:`s` 中的一个**最短连续子串**,要求这个子串包含 `t` 中的**每一个字符**(包括重复字符的数量也要满足)。如果不存在,返回空字符串 `""`。题目保证答案唯一。 +- **关键点**:不仅要包含 t 中的所有字符种类,每个字符出现的次数也要 ≥ t 中该字符出现的次数。例如 t = `"aa"`,子串中必须有至少两个 `'a'`。 +- **具体例子**: + - `s = "ADOBECODEBANC", t = "ABC"` → 输出 `"BANC"`(包含 A、B、C 各一个,长度为 4,比 `"ADOBEC"` 长度 6 更短)。 + - `s = "a", t = "a"` → 输出 `"a"`。 + - `s = "a", t = "aa"` → 输出 `""`(s 中只有一个 a,不够两个)。 + +--- +## 解法一:暴力枚举(理解用) +> 原则:枚举所有子串,检查每个子串是否覆盖 t,记录最短的。 + +### 思路 +1. **为什么想到这种方法**:要找满足条件的子串,最直接的方法就是把所有可能的子串都检查一遍。 +2. **步骤分解**: + - 先统计 `t` 中每个字符需要的数量,存入字典 `need`。 + - 枚举所有子串的起点 i 和终点 j(i ≤ j)。 + - 对每个子串 `s[i:j+1]`,统计其中每个字符的出现次数,与 `need` 比较,看是否所有字符都满足 `count[ch] >= need[ch]`。 + - 如果满足且长度更短,更新答案。 +3. **缺点**:时间复杂度 O(m³)(枚举 O(m²) × 统计 O(m)),完全不可行。 + +### 代码(省略,因为太慢且不实用) + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m³) | 枚举所有子串 O(m²),每个子串统计 O(m) | +| 空间 | O(字符集) | 存储字符计数 | + +--- +## 解法二:滑动窗口(最优解法) +> 改进点:使用滑动窗口 + 双指针,在 O(m) 时间内找到最小覆盖子串。 + +### 思路 +1. **为什么想到这种方法**:这是**滑动窗口**的经典应用。我们需要一个窗口 `[left, right]` 包含 t 的所有字符,然后尝试缩小左边界来找到更短的窗口。 +2. **核心思想**: + - 使用两个指针 `left` 和 `right`,初始都指向 0。 + - 移动右指针 `right` 扩大窗口,直到窗口**包含**了 t 的所有字符(即“可行解”)。 + - 然后尝试移动左指针 `left` 缩小窗口,同时保持窗口仍然包含 t 的所有字符,记录最短的窗口长度。 + - 重复上述过程,直到右指针到达末尾。 +3. **如何判断窗口是否包含 t 的所有字符**: + - 用字典 `need` 记录 t 中每个字符还需要的数量(初始值 = t 中字符出现次数)。 + - 用字典 `window` 记录当前窗口中每个字符的出现次数。 + - 维护一个变量 `formed`,表示当前窗口中已经满足了 `need` 中多少个字符(即 `window[ch] >= need[ch]` 的字符种类数)。 + - 当 `formed == len(need)`(即所有需要的字符种类都满足了),说明当前窗口是可行的。 +4. **步骤分解**: + - 统计 `t` 中每个字符的需求量 `need`。 + - 初始化 `left = 0, right = 0, formed = 0`。 + - 初始化 `window` 字典为空。 + - 初始化答案:`ans_len = 无穷大, ans_left = -1`。 + - 循环 `right` 从 0 到 m-1: + - 将 `s[right]` 加入窗口,更新 `window` 计数。 + - 如果当前字符在 `need` 中,且 `window[ch] == need[ch]`(注意是等于,不是大于等于),说明这个字符的需求刚好被满足,`formed += 1`。 + - 当 `formed == len(need)` 时(窗口可行),尝试缩小左边界: + - 更新答案:如果当前窗口长度 `right-left+1` 小于 `ans_len`,则记录 `ans_len` 和 `ans_left`。 + - 将 `s[left]` 移出窗口:如果移出的字符在 `need` 中,且 `window[ch] == need[ch]`,说明移出后该字符不再满足需求,`formed -= 1`。 + - `window[s[left]] -= 1`,`left += 1`。 + - 最后,如果 `ans_len` 仍是无穷大,返回 `""`;否则返回 `s[ans_left:ans_left+ans_len]`。 + +### 代码 +```python +class Solution: + def minWindow(self, s, t): + """ + 滑动窗口 + 双指针 + """ + if not s or not t: + return "" + + # 统计 t 中每个字符的需求量 + need = {} + for ch in t: + need[ch] = need.get(ch, 0) + 1 + + # 窗口内字符的计数 + window = {} + + left = 0 + right = 0 + formed = 0 # 已经满足需求的字符种类数 + required = len(need) # 总共需要的字符种类数 + + # 答案记录: [窗口长度, 左边界] + ans_len = float('inf') + ans_left = -1 + + # 移动右指针扩大窗口 + while right < len(s): + ch = s[right] + window[ch] = window.get(ch, 0) + 1 + + # 如果当前字符是需要的,并且窗口中的数量刚好等于需求量 + if ch in need and window[ch] == need[ch]: + formed += 1 + + # 当窗口满足条件时,尝试缩小左边界 + while left <= right and formed == required: + ch_left = s[left] + + # 更新答案 + current_len = right - left + 1 + if current_len < ans_len: + ans_len = current_len + ans_left = left + + # 移出左边字符 + window[ch_left] -= 1 + if ch_left in need and window[ch_left] < need[ch_left]: + formed -= 1 + + left += 1 + + right += 1 + + if ans_len == float('inf'): + return "" + return s[ans_left:ans_left + ans_len] + +# 测试 +sol = Solution() +print(sol.minWindow("ADOBECODEBANC", "ABC")) # "BANC" +print(sol.minWindow("a", "a")) # "a" +print(sol.minWindow("a", "aa")) # "" +print(sol.minWindow("aa", "aa")) # "aa" +print(sol.minWindow("ab", "b")) # "b" +``` + +### 手动模拟(`s = "ADOBECODEBANC", t = "ABC"`) +**need** = `{'A':1, 'B':1, 'C':1}`, required = 3 + +| right | char | window 状态 | formed | 是否可行 | left 移动 | 记录答案 | +|-------|------|-------------|--------|----------|-----------|----------| +| 0 | A | {A:1} | 1 | 否 | - | - | +| 1 | D | {A:1, D:1} | 1 | 否 | - | - | +| 2 | O | {A:1, D:1, O:1} | 1 | 否 | - | - | +| 3 | B | {A:1, B:1, D:1, O:1} | 2 | 否 | - | - | +| 4 | E | {A:1, B:1, E:1, D:1, O:1} | 2 | 否 | - | - | +| 5 | C | {A:1, B:1, C:1, ...} | 3 | **是** | 尝试缩小 left=0: 移出 A → formed=2, left=1; 仍可行? 检查窗口 {B:1,C:1,...} 缺 A → formed=2, 停止 | 记录 `"ADOBEC"`(len=6) | +| right=5 继续循环内 while | - | - | - | 否 | - | - | +| 6 | O | {A:0, B:1, C:1, O:2, ...} | 2 | 否 | - | - | +| 7 | D | ... | 2 | 否 | - | - | +| 8 | E | ... | 2 | 否 | - | - | +| 9 | B | {B:2, ...} | 2 | 否 | - | - | +| 10 | A | {A:1, B:2, C:1, ...} | 3 | **是** | 缩小 left=1: 移出 D(不在need) → left=2; 移出 O → left=3; 移出 B → formed=2, left=4; 停止 | 记录 `"CODEBA"`(len=6) 不更新 | +| right=10 继续 | - | - | - | 否 | - | - | +| 11 | N | ... | 2 | 否 | - | - | +| 12 | C | {C:2, ...} | 3 | **是** | 缩小: 移出 B(left=4) → formed=2? 实际窗口 `[5..12]`="EBANC" → 检查: 移出 E(不在need), 移出 B → formed=2, left=6; 移出 A → formed=2? 继续... 最终 left=7 时窗口 "ANC" 缺 B, 停止 | 记录 `"BANC"`(len=4) 更新最短 | + +最终答案 = `"BANC"` ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m + n) | 每个字符最多被 left 和 right 指针各访问一次,统计 t 需要 O(n) | +| 空间 | O(字符集) | need 和 window 字典最多存储 52 个键(大小写字母),可视为 O(1) | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +| -------- | -------- | ------ | ----------- | --------------------- | +| 解法一:暴力枚举 | O(m³) | O(字符集) | 思路简单 | 完全不可行 | +| 解法二:滑动窗口 | O(m + n) | O(字符集) | 时间最优,面试标准解法 | 需要仔细处理 `formed` 的更新条件 | + +**推荐场景**: +- 初学阶段:理解滑动窗口的两阶段(扩大窗口找可行解 + 缩小窗口优化解)。 +- 面试阶段:必须掌握滑动窗口解法。这是 LeetCode 上最经典的滑动窗口题目之一,理解本题后,类似的题目(如 438. 找到字符串中所有字母异位词、567. 字符串的排列)都可以迎刃而解。 + +**易错提醒**: +- `formed` 增加的条件是 `window[ch] == need[ch]`,而不是 `>=`。因为当窗口数量超过需求时,该字符已经满足,不需要重复计数。 +- 缩小左边界时,移出字符后判断 `window[ch] < need[ch]` 才减少 `formed`。如果移出后仍然 `>=`,该字符仍满足,`formed` 不变。 +- 注意 `left <= right` 和 `formed == required` 的循环条件,避免死循环。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(13)53. 最大子数组和.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(13)53. 最大子数组和.md new file mode 100644 index 0000000..dea9010 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(13)53. 最大子数组和.md @@ -0,0 +1,217 @@ +**标签**:数组、动态规划、分治法、贪心 + +## 题目理解 +- **输入**:一个整数数组 `nums`,长度 n(1 ≤ n ≤ 10⁵)。数组元素范围 -10⁴ 到 10⁴。 +- **输出**:一个整数,表示所有连续子数组中的最大和。子数组至少包含一个元素。 +- **关键点**:子数组必须是连续的,不能跳过元素。元素可以是负数。 +- **具体例子**: + - `nums = [-2,1,-3,4,-1,2,1,-5,4]` → 最大子数组 `[4,-1,2,1]`,和为 6。 + - `nums = [1]` → 最大和就是 1。 + - `nums = [5,4,-1,7,8]` → 整个数组和最大,为 23。 + - `nums = [-1,-2,-3]` → 最大子数组是 `[-1]`,和为 -1(不能选空数组)。 + +--- +## 解法一:暴力枚举(理解用) +> 原则:最直观的方法,枚举所有子数组,计算每个子数组的和。 + +### 思路 +1. **为什么想到这种方法**:要找最大和的连续子数组,最直接的方法就是枚举所有可能的起点和终点,计算每个子数组的和,取最大值。 +2. **步骤分解**: + - 用两层循环:外层循环 i 表示子数组起点,内层循环 j 从 i 到 n-1 表示终点。 + - 对于每个起点 i,维护一个累加和 `current_sum`,每次加上 `nums[j]` 得到子数组 `[i..j]` 的和。 + - 用 `max_sum` 记录遇到的最大和。 + +### 代码 +```python +class Solution: + def maxSubArray(self, nums): + """ + 暴力枚举所有子数组 + """ + n = len(nums) + max_sum = float('-inf') # 初始化为负无穷 + + # 枚举所有起点 + for i in range(n): + current_sum = 0 + # 枚举所有终点 + for j in range(i, n): + current_sum += nums[j] + if current_sum > max_sum: + max_sum = current_sum + + return max_sum + +# 测试 +sol = Solution() +print(sol.maxSubArray([-2,1,-3,4,-1,2,1,-5,4])) # 6 +print(sol.maxSubArray([1])) # 1 +print(sol.maxSubArray([5,4,-1,7,8])) # 23 +print(sol.maxSubArray([-1,-2,-3])) # -1 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n²) | 两层循环,总子数组个数为 n(n+1)/2 | +| 空间 | O(1) | 只用了几个变量 | + +### 边界情况 +- **数组长度为 1**:直接返回该元素。 +- **全为负数**:最大和是最大的那个负数(即最接近 0 的负数)。 +- **全为正数**:最大和是整个数组的和。 + +--- +## 解法二:动态规划(Kadane 算法) +> 改进点:将 O(n²) 降到 O(n),通过状态转移避免重复计算。 + +### 思路 +1. **为什么想到这种方法**:定义 `dp[i]` 表示**以 `nums[i]` 结尾**的连续子数组的最大和。那么对于每个位置 i,要么把 `nums[i]` 加到前面的子数组上(`dp[i-1] + nums[i]`),要么重新开始一个新的子数组(`nums[i]` 自己)。取两者中较大的。 +2. **状态转移方程**:`dp[i] = max(dp[i-1] + nums[i], nums[i])` +3. **步骤分解**: + - 初始化 `dp[0] = nums[0]`,`max_sum = nums[0]`。 + - 遍历 i 从 1 到 n-1: + - `dp[i] = max(dp[i-1] + nums[i], nums[i])` + - 更新 `max_sum = max(max_sum, dp[i])` + - 返回 `max_sum` +4. **空间优化**:由于 `dp[i]` 只依赖于 `dp[i-1]`,可以用一个变量滚动存储,不需要数组。 + +### 代码 +```python +class Solution: + def maxSubArray(self, nums): + """ + 动态规划(Kadane 算法) + dp[i] = 以 nums[i] 结尾的最大子数组和 + """ + n = len(nums) + # dp_prev 表示 dp[i-1] + dp_prev = nums[0] + max_sum = nums[0] + + for i in range(1, n): + # 要么续接前面的子数组,要么从当前元素重新开始 + dp_curr = max(dp_prev + nums[i], nums[i]) + max_sum = max(max_sum, dp_curr) + dp_prev = dp_curr + + return max_sum + +# 测试 +sol = Solution() +print(sol.maxSubArray([-2,1,-3,4,-1,2,1,-5,4])) # 6 +print(sol.maxSubArray([1])) # 1 +print(sol.maxSubArray([5,4,-1,7,8])) # 23 +print(sol.maxSubArray([-1,-2,-3])) # -1 +``` + +### 手动模拟(`nums = [-2,1,-3,4,-1,2,1,-5,4]`) +| i | nums[i] | dp_prev (前一个 dp) | dp_curr = max(dp_prev+nums[i], nums[i]) | max_sum | +|---|---------|---------------------|------------------------------------------|---------| +| 0 | -2 | -2 | -2 | -2 | +| 1 | 1 | -2 | max(-2+1= -1, 1) = 1 | max(-2,1)=1 | +| 2 | -3 | 1 | max(1-3= -2, -3) = -2 | max(1,-2)=1 | +| 3 | 4 | -2 | max(-2+4=2, 4) = 4 | max(1,4)=4 | +| 4 | -1 | 4 | max(4-1=3, -1) = 3 | max(4,3)=4 | +| 5 | 2 | 3 | max(3+2=5, 2) = 5 | max(4,5)=5 | +| 6 | 1 | 5 | max(5+1=6, 1) = 6 | max(5,6)=6 | +| 7 | -5 | 6 | max(6-5=1, -5) = 1 | max(6,1)=6 | +| 8 | 4 | 1 | max(1+4=5, 4) = 5 | max(6,5)=6 | + +最终 `max_sum = 6` ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 一次遍历 | +| 空间 | O(1) | 只用了两个变量 | + +--- +## 解法三:分治法(进阶) +> 说明:题目进阶要求尝试分治法。时间复杂度 O(n log n),虽然不如动态规划 O(n) 快,但展示了“分而治之”的思想。 + +### 思路 +1. **为什么想到这种方法**:最大子数组和要么完全在左半部分,要么完全在右半部分,要么跨越中点。递归地计算左右部分的最大子数组和,再计算跨越中点的最大子数组和,三者取最大值。 +2. **步骤分解**: + - 递归函数 `divide(l, r)` 返回区间 `[l, r]` 内的最大子数组和。 + - 如果 `l == r`,返回 `nums[l]`。 + - 计算中点 `mid = (l + r) // 2`。 + - 递归计算左半部分最大和 `left_max`,右半部分最大和 `right_max`。 + - 计算跨越中点的最大和: + - 从中点向左扫描,记录以中点为右端点的最大和(包含中点)。 + - 从中点向右扫描,记录以中点为左端点的最大和(包含中点)。 + - 跨越中点的最大和 = 左边部分 + 右边部分 - `nums[mid]`(因为中点被加了两次,或者分别记录左右包含中点的最大和再相加)。 + - 返回 `max(left_max, right_max, cross_max)`。 + +### 代码 +```python +class Solution: + def maxSubArray(self, nums): + """ + 分治法 + """ + def divide(l, r): + # 递归终止:只有一个元素 + if l == r: + return nums[l] + + mid = (l + r) // 2 + + # 左半部分最大和 + left_max = divide(l, mid) + # 右半部分最大和 + right_max = divide(mid + 1, r) + + # 计算跨越中点的最大和 + # 从中点向左扫描 + left_sum = float('-inf') + curr = 0 + for i in range(mid, l - 1, -1): + curr += nums[i] + if curr > left_sum: + left_sum = curr + + # 从中点向右扫描 + right_sum = float('-inf') + curr = 0 + for i in range(mid + 1, r + 1): + curr += nums[i] + if curr > right_sum: + right_sum = curr + + cross_max = left_sum + right_sum + + return max(left_max, right_max, cross_max) + + return divide(0, len(nums) - 1) + +# 测试 +sol = Solution() +print(sol.maxSubArray([-2,1,-3,4,-1,2,1,-5,4])) # 6 +print(sol.maxSubArray([1])) # 1 +print(sol.maxSubArray([5,4,-1,7,8])) # 23 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n log n) | 递归深度 log n,每层扫描 O(n) | +| 空间 | O(log n) | 递归调用栈深度 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力枚举 | O(n²) | O(1) | 思路最简单 | n=10⁵ 时严重超时 | +| 解法二:动态规划 | O(n) | O(1) | 时间最优,代码简洁 | 需要理解状态转移 | +| 解法三:分治法 | O(n log n) | O(log n) | 展示分治思想 | 比动态规划慢,代码复杂 | + +**推荐场景**: +- 初学阶段:理解暴力枚举,确认问题定义。 +- 面试阶段:**必须用动态规划(Kadane 算法)**,这是最经典的一维 DP 问题,代码极简且效率最高。 +- 进阶要求:如果面试官问“能否用分治法”,可以写出解法三,体现算法多样性。但日常解题优先用动态规划。 + +**易错提醒**: +- 初始化 `max_sum` 不能设为 0,因为数组可能全为负数,正确答案应为负数而非 0。应设为 `nums[0]` 或 `float('-inf')`。 +- Kadane 算法的核心是:`dp[i] = max(nums[i], dp[i-1] + nums[i])`,记住这个公式即可。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(14)56. 合并区间.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(14)56. 合并区间.md new file mode 100644 index 0000000..4571854 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(14)56. 合并区间.md @@ -0,0 +1,154 @@ +**标签**:数组、排序、区间合并、双指针 + +# 合并区间 + +## 题目理解 +- **输入**:一个二维数组 `intervals`,其中每个元素 `intervals[i] = [start_i, end_i]` 表示一个闭区间。区间数量 n 满足 1 ≤ n ≤ 10⁴。每个区间的起点和终点满足 0 ≤ start_i ≤ end_i ≤ 10⁴。 +- **输出**:合并所有重叠区间后的结果,返回一个二维数组,其中的区间互不重叠,且按起点升序排列。 +- **关键点**:什么是“重叠”?如果区间 A 的终点 ≥ 区间 B 的起点,且区间 A 的起点 ≤ 区间 B 的终点,则它们重叠。特别地,`[1,4]` 和 `[4,5]` 被视为重叠(因为 4 = 4),合并后为 `[1,5]`。 +- **具体例子**: + - `intervals = [[1,3],[2,6],[8,10],[15,18]]` → 输出 `[[1,6],[8,10],[15,18]]` + - `intervals = [[1,4],[4,5]]` → 输出 `[[1,5]]` + - `intervals = [[4,7],[1,4]]` → 输出 `[[1,7]]`(注意输入未排序) + +--- +## 解法一:暴力法(理解用) +> 原则:最直观的方法,不断循环合并重叠区间,直到无法再合并。 + +### 思路 +1. **为什么想到这种方法**:每次找出所有重叠的区间对,将它们合并成一个新区间,重复这个过程直到没有区间可以合并。 +2. **步骤分解**: + - 将输入转换为列表(方便修改)。 + - 设置一个标志 `merged`,初始为 `True`,表示本轮是否有合并发生。 + - 当 `merged` 为 `True` 时循环: + - 设置 `merged = False`。 + - 遍历所有区间对 `(i, j)`,如果 `i != j` 且两个区间重叠,则合并它们: + - 新区间 = `[min(start_i, start_j), max(end_i, end_j)]`。 + - 删除原来的两个区间,加入新区间。 + - 设置 `merged = True`,并跳出内层循环(因为列表长度改变,需要重新开始)。 + - 返回最终的区间列表。 +3. **缺点**:时间复杂度很高,区间数量多时效率低。 + +### 代码(简略版,不推荐实际使用) +```python +class Solution: + def merge(self, intervals): + # 此方法仅用于理解思路,实际不推荐使用 + intervals = [list(interval) for interval in intervals] + changed = True + while changed: + changed = False + n = len(intervals) + for i in range(n): + for j in range(i+1, n): + a, b = intervals[i], intervals[j] + # 判断是否重叠:a的终点 >= b的起点 且 a的起点 <= b的终点 + if not (a[1] < b[0] or b[1] < a[0]): # 不满足不重叠条件即重叠 + # 合并 + new_start = min(a[0], b[0]) + new_end = max(a[1], b[1]) + intervals[i] = [new_start, new_end] + intervals.pop(j) + changed = True + break + if changed: + break + return intervals +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n³) | 最坏情况下每轮合并一个区间,每轮 O(n²),共 O(n) 轮 | +| 空间 | O(1) | 原地修改 | + +--- +## 解法二:排序 + 贪心(最优解法) +> 改进点:先按区间起点排序,然后一次遍历合并,将 O(n³) 降到 O(n log n)。 + +### 思路 +1. **为什么想到这种方法**:如果区间按照起点排序,那么能够合并的区间一定是连续的。我们只需要维护当前合并后的区间,然后依次检查下一个区间是否能与它合并。 +2. **核心逻辑**: + - 先按每个区间的起点(`start`)升序排序。 + - 初始化结果列表 `merged`,将第一个区间放入。 + - 遍历剩余的每个区间 `[start, end]`: + - 设 `merged` 中最后一个区间为 `[last_start, last_end]`。 + - 如果 `start <= last_end`(当前区间与最后一个区间重叠),则合并:`last_end = max(last_end, end)`。 + - 否则,不重叠,直接将当前区间加入 `merged`。 +3. **为什么排序后可行**:排序后,当前区间的起点一定 ≥ 上一个区间的起点。所以只需要比较当前区间的起点和上一个区间的终点,就能判断是否重叠。如果重叠,更新终点为两者较大值。 + +### 代码 +```python +class Solution: + def merge(self, intervals): + """ + 排序 + 贪心合并 + """ + if not intervals: + return [] + + # 按照每个区间的起点排序 + # key=lambda x: x[0] 表示按每个子列表的第一个元素排序 + intervals.sort(key=lambda x: x[0]) + + merged = [intervals[0]] # 结果列表,初始放入第一个区间 + + for curr_start, curr_end in intervals[1:]: + # 获取结果列表中最后一个区间 + last_start, last_end = merged[-1] + + # 检查是否重叠:当前区间的起点 <= 最后一个区间的终点 + if curr_start <= last_end: + # 重叠,合并:更新最后一个区间的终点为两者较大值 + merged[-1][1] = max(last_end, curr_end) + else: + # 不重叠,直接添加当前区间 + merged.append([curr_start, curr_end]) + + return merged + +# 测试 +sol = Solution() +print(sol.merge([[1,3],[2,6],[8,10],[15,18]])) # [[1,6],[8,10],[15,18]] +print(sol.merge([[1,4],[4,5]])) # [[1,5]] +print(sol.merge([[4,7],[1,4]])) # [[1,7]](排序后变成[[1,4],[4,7]]) +print(sol.merge([[1,4],[0,4]])) # [[0,4]](排序后[[0,4],[1,4]],合并为[0,4]) +print(sol.merge([[1,4],[0,1]])) # [[0,4]] +``` + +### 手动模拟(`intervals = [[1,3],[2,6],[8,10],[15,18]]`) +1. 排序后:`[[1,3],[2,6],[8,10],[15,18]]`(已有序) +2. `merged = [[1,3]]` +3. 处理 `[2,6]`:`2 <= 3`(重叠),合并 → `merged = [[1, max(3,6)=6]]` = `[[1,6]]` +4. 处理 `[8,10]`:`8 > 6`(不重叠),添加 → `merged = [[1,6],[8,10]]` +5. 处理 `[15,18]`:`15 > 10`(不重叠),添加 → `merged = [[1,6],[8,10],[15,18]]` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n log n) | 排序需要 O(n log n),遍历一次 O(n) | +| 空间 | O(1) 或 O(n) | 排序的空间复杂度取决于算法(Python 的 Timsort 是 O(n)),结果数组不算额外空间 | + +### 边界情况 +- **空数组**:`intervals = []`,直接返回 `[]`(题目保证 n ≥ 1,但防御性编程可加)。 +- **只有一个区间**:直接返回原数组。 +- **完全重叠**:如 `[[1,4],[1,4],[1,4]]`,合并后为 `[[1,4]]`。 +- **首尾相接**:如 `[[1,4],[4,5]]`,被视为重叠,合并为 `[1,5]`。 +- **未排序输入**:如 `[[4,7],[1,4]]`,排序后变为 `[[1,4],[4,7]]`,然后合并为 `[[1,7]]`。 + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力合并 | O(n³) | O(1) | 思路直接 | 效率极低,不可用 | +| 解法二:排序+贪心 | O(n log n) | O(1) 或 O(n) | 时间优,代码简洁,面试标准解法 | 需要理解排序后合并的正确性 | + +**推荐场景**: +- 初学阶段:理解重叠的判断条件(`start <= last_end`)和合并操作(更新终点为最大值)。 +- 面试阶段:**必须用排序+贪心解法**。这是区间问题的经典模板,类似题目(如 435. 无重叠区间、452. 用最少数量的箭引爆气球)都可以用排序后贪心的思想。 + +**易错提醒**: +- 排序时注意:按起点排序,而不是按终点。 +- 合并条件是 `curr_start <= last_end`(注意包含等号,因为 `[1,4]` 和 `[4,5]` 重叠)。 +- 合并后更新的是 `last_end = max(last_end, curr_end)`,而不是直接赋值 `curr_end`(因为可能存在 `[1,10], [2,4]` 这种情况,`[2,4]` 完全被包含,终点应保持 10)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(15)189. 轮转数组.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(15)189. 轮转数组.md new file mode 100644 index 0000000..a40a49a --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(15)189. 轮转数组.md @@ -0,0 +1,223 @@ +**标签**:数组、数学、双指针、原地操作 + +# 轮转数组 + +## 题目理解 +- **输入**:一个整数数组 `nums`(长度 n,1 ≤ n ≤ 10⁵)和一个非负整数 `k`(0 ≤ k ≤ 10⁵)。 +- **输出**:**原地修改**数组,将每个元素向右移动 `k` 个位置。超出数组末尾的元素会循环到开头。 +- **关键点**:当 `k` 很大时(例如 `k = 10⁵`),实际上可以简化:轮转 `k` 步等价于轮转 `k % n` 步,因为轮转 n 次数组恢复原状。 +- **具体例子**: + - `nums = [1,2,3,4,5,6,7], k = 3` → 输出 `[5,6,7,1,2,3,4]` + - `nums = [-1,-100,3,99], k = 2` → 输出 `[3,99,-1,-100]` + - `nums = [1,2], k = 3` → 实际移动 3 % 2 = 1 步 → `[2,1]` + +--- +## 解法一:使用额外数组(最简单) +> 原则:最直观的方法,创建一个新数组,直接计算每个元素的新位置。 + +### 思路 +1. **为什么想到这种方法**:每个元素向右移动 k 步后,新位置 = `(原位置 + k) % n`。我们可以创建一个大小相同的新数组,遍历原数组,将元素放到新数组的对应位置。 +2. **步骤分解**: + - 获取数组长度 `n`,计算实际移动步数 `k = k % n`(如果 k ≥ n)。 + - 创建新数组 `rotated`,长度 n。 + - 遍历 i 从 0 到 n-1: + - 计算新位置 `new_index = (i + k) % n` + - 将 `nums[i]` 放到 `rotated[new_index]` + - 将 `rotated` 复制回 `nums`(因为题目要求原地修改)。 + +### 代码 +```python +class Solution: + def rotate(self, nums, k): + """ + 使用额外数组 + """ + n = len(nums) + k = k % n # 处理 k > n 的情况 + if k == 0: + return + + rotated = [0] * n # 创建新数组,初始全为0 + + for i in range(n): + new_index = (i + k) % n + rotated[new_index] = nums[i] + + # 将结果复制回原数组(原地修改) + for i in range(n): + nums[i] = rotated[i] + +# 测试 +sol = Solution() +nums1 = [1,2,3,4,5,6,7] +sol.rotate(nums1, 3) +print(nums1) # [5,6,7,1,2,3,4] + +nums2 = [-1,-100,3,99] +sol.rotate(nums2, 2) +print(nums2) # [3,99,-1,-100] + +nums3 = [1,2] +sol.rotate(nums3, 3) +print(nums3) # [2,1](3 % 2 = 1 步) +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 遍历两次数组(一次构建,一次复制) | +| 空间 | O(n) | 额外创建了一个长度为 n 的数组 | + +### 边界情况 +- **k = 0**:数组不变,直接返回。 +- **k 是 n 的倍数**:`k % n = 0`,数组不变。 +- **n = 1**:只有一个元素,无论 k 多大,数组不变。 + +--- +## 解法二:多次反转(最优解法,原地 O(1) 空间) +> 改进点:使用三次反转,不需要额外数组,空间复杂度 O(1)。 + +### 思路 +1. **为什么想到这种方法**:观察轮转后的数组,发现它由两部分组成:原数组的后 k 个元素(移动到前面),以及前 n-k 个元素(移动到后面)。通过三次反转可以达到这个效果: + - 反转整个数组 → 后 k 个元素变到前面,但顺序是反的。 + - 反转前 k 个元素 → 恢复正确的顺序。 + - 反转后 n-k 个元素 → 恢复正确的顺序。 +2. **步骤分解**(以 `nums = [1,2,3,4,5,6,7], k = 3` 为例): + - 先处理 `k = k % n`。 + - 反转整个数组:`[7,6,5,4,3,2,1]` + - 反转前 k 个元素(索引 0~k-1):反转 `[7,6,5]` → `[5,6,7]`,数组变为 `[5,6,7,4,3,2,1]` + - 反转后 n-k 个元素(索引 k~n-1):反转 `[4,3,2,1]` → `[1,2,3,4]`,数组变为 `[5,6,7,1,2,3,4]` +3. **为什么需要三次反转**:第一次反转把后 k 个元素放到前面,但顺序反了;后两次反转分别修复两部分内部的顺序。 + +### 代码 +```python +class Solution: + def rotate(self, nums, k): + """ + 三次反转法(原地,O(1) 空间) + """ + n = len(nums) + k = k % n + if k == 0: + return + + # 辅助函数:反转数组的一部分 [left, right](闭区间) + def reverse(left, right): + while left < right: + nums[left], nums[right] = nums[right], nums[left] + left += 1 + right -= 1 + + # 1. 反转整个数组 + reverse(0, n - 1) + # 2. 反转前 k 个元素 + reverse(0, k - 1) + # 3. 反转后 n - k 个元素 + reverse(k, n - 1) + +# 测试 +sol = Solution() +nums1 = [1,2,3,4,5,6,7] +sol.rotate(nums1, 3) +print(nums1) # [5,6,7,1,2,3,4] + +nums2 = [-1,-100,3,99] +sol.rotate(nums2, 2) +print(nums2) # [3,99,-1,-100] + +nums3 = [1,2] +sol.rotate(nums3, 3) +print(nums3) # [2,1] +``` + +### 手动模拟 +初始:`[1,2,3,4,5,6,7]`, k=3 +1. 反转整个数组:`[7,6,5,4,3,2,1]` +2. 反转前 3 个:`[5,6,7,4,3,2,1]` +3. 反转后 4 个:`[5,6,7,1,2,3,4]` ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 每个元素被反转两次(整体反转 + 部分反转),共 O(n) | +| 空间 | O(1) | 只用了几个变量,没有额外数组 | + +--- +## 解法三:环状替换(原地,另一种思路) +> 说明:直接从数学上模拟元素的移动轨迹,每次将一个元素放到它的最终位置,同时将被覆盖的元素继续移动,直到所有元素都被移动一次。 + +### 思路 +1. **为什么想到这种方法**:每个元素向右移动 k 步,形成多个循环链。例如 n=6, k=2,索引移动轨迹:0→2→4→0(一个循环),1→3→5→1(另一个循环)。我们可以逐个循环处理,每个循环内依次移动元素。 +2. **步骤分解**: + - 计算需要处理的循环个数 = `gcd(n, k)`(最大公约数)。 + - 对于每个循环的起点 `start`(从 0 到 `gcd-1`): + - 记录当前位置 `current = start`,要移动的元素 `prev = nums[start]`。 + - 循环:计算下一个位置 `next = (current + k) % n`,交换 `prev` 和 `nums[next]`,然后 `current = next`。 + - 当 `next == start` 时,该循环结束。 +3. **为什么是 gcd(n, k)**:从任意起点开始,每次前进 k 步,经过 `n / gcd(n, k)` 步后会回到起点。不同的起点会形成不同的循环,循环的个数就是 `gcd(n, k)`。 + +### 代码 +```python +import math + +class Solution: + def rotate(self, nums, k): + """ + 环状替换法 + """ + n = len(nums) + k = k % n + if k == 0: + return + + # 计算需要处理的循环个数 + cycles = math.gcd(n, k) + + for start in range(cycles): + current = start + prev = nums[start] + + # 循环移动,直到回到起点 + while True: + next_idx = (current + k) % n + # 交换 prev 和 nums[next_idx] + nums[next_idx], prev = prev, nums[next_idx] + current = next_idx + if current == start: + break + +# 测试 +sol = Solution() +nums1 = [1,2,3,4,5,6,7] +sol.rotate(nums1, 3) +print(nums1) # [5,6,7,1,2,3,4] + +nums2 = [-1,-100,3,99] +sol.rotate(nums2, 2) +print(nums2) # [3,99,-1,-100] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 每个元素被移动恰好一次 | +| 空间 | O(1) | 只用了几个变量 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:额外数组 | O(n) | O(n) | 最简单直观,不易错 | 需要额外空间 | +| 解法二:三次反转 | O(n) | O(1) | 原地操作,面试经典解法 | 需要理解反转逻辑 | +| 解法三:环状替换 | O(n) | O(1) | 原地操作,数学上优美 | 需要理解 gcd 和循环轨迹 | + +**推荐场景**: +- 初学阶段:用解法一快速实现,理解轮转的基本逻辑。 +- 面试阶段:**优先用解法二(三次反转)**,代码简洁且容易解释,是本题的标准答案。解法三也可以,但需要解释 `gcd(n, k)` 的来源。 +- 进阶要求:如果面试官追问“能否不用额外数组”,解法二和解法三都满足 O(1) 空间。 + +**易错提醒**: +- 务必先处理 `k = k % n`,否则当 k > n 时可能会做多余操作(虽然不影响结果,但效率低)。 +- 三次反转法中,注意反转的范围:第一次整个数组,第二次前 k 个,第三次从 k 到末尾。 +- 如果 `k == 0` 或 `k % n == 0`,直接返回,避免无效操作。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(16)238. 除了自身以外数组的乘积.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(16)238. 除了自身以外数组的乘积.md new file mode 100644 index 0000000..4966d06 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(16)238. 除了自身以外数组的乘积.md @@ -0,0 +1,172 @@ +**标签**:数组、前缀积、后缀积、原地操作 + +# 除了自身以外数组的乘积 + +## 题目理解 +- **输入**:一个整数数组 `nums`,长度 n(2 ≤ n ≤ 10⁵)。数组元素范围 -30 到 30。题目保证所有乘积结果在 32 位整数范围内。 +- **输出**:一个整数数组 `answer`,其中 `answer[i]` 等于 `nums` 中除了 `nums[i]` 之外所有元素的乘积。 +- **关键约束**: + - **不能使用除法**(否则可以先算总乘积,再除以 `nums[i]`,但遇到 0 会出问题)。 + - **时间复杂度 O(n)**。 + - **空间复杂度可选 O(1)**(输出数组不计入额外空间)。 +- **具体例子**: + - `nums = [1,2,3,4]` → 输出 `[24,12,8,6]` + - answer[0] = 2×3×4 = 24 + - answer[1] = 1×3×4 = 12 + - answer[2] = 1×2×4 = 8 + - answer[3] = 1×2×3 = 6 + - `nums = [-1,1,0,-3,3]` → 输出 `[0,0,9,0,0]`(因为第 2 个元素是 0,任何包含它的乘积都是 0) + +--- +## 解法一:前缀积 + 后缀积(使用额外数组) +> 原则:最直观的 O(n) 方法,用两个数组分别记录每个位置左边所有元素的乘积和右边所有元素的乘积。 + +### 思路 +1. **为什么想到这种方法**:`answer[i]` = `nums[0]×...×nums[i-1]` × `nums[i+1]×...×nums[n-1]`,即**左边所有元素的乘积** × **右边所有元素的乘积**。我们可以先计算每个位置左边的乘积,再计算右边的乘积,最后相乘。 +2. **步骤分解**: + - 创建数组 `left`,长度 n。`left[i]` 表示 `nums[0]` 到 `nums[i-1]` 的乘积(即 i 左边所有元素乘积)。`left[0] = 1`(左边没有元素)。 + - 创建数组 `right`,长度 n。`right[i]` 表示 `nums[i+1]` 到 `nums[n-1]` 的乘积(即 i 右边所有元素乘积)。`right[n-1] = 1`(右边没有元素)。 + - 遍历计算 `left`:`left[i] = left[i-1] × nums[i-1]` + - 遍历计算 `right`:`right[i] = right[i+1] × nums[i+1]`(从右向左) + - 遍历计算 `answer[i] = left[i] × right[i]` + +### 代码 +```python +class Solution: + def productExceptSelf(self, nums): + """ + 使用左右两个辅助数组 + """ + n = len(nums) + + # left[i] 表示 i 左边所有元素的乘积 + left = [1] * n + for i in range(1, n): + left[i] = left[i-1] * nums[i-1] + + # right[i] 表示 i 右边所有元素的乘积 + right = [1] * n + for i in range(n-2, -1, -1): + right[i] = right[i+1] * nums[i+1] + + # 计算结果 + answer = [left[i] * right[i] for i in range(n)] + + return answer + +# 测试 +sol = Solution() +print(sol.productExceptSelf([1,2,3,4])) # [24,12,8,6] +print(sol.productExceptSelf([-1,1,0,-3,3])) # [0,0,9,0,0] +print(sol.productExceptSelf([2,3,4,5])) # [60,40,30,24] +``` + +### 手动模拟(`nums = [1,2,3,4]`) +| i | left[i] | right[i] | answer[i] | +|---|---------|----------|-----------| +| 0 | 1 | 2×3×4=24 | 1×24=24 | +| 1 | 1×1=1 | 3×4=12 | 1×12=12 | +| 2 | 1×1×2=2 | 4=4 | 2×4=8 | +| 3 | 1×1×2×3=6 | 1 | 6×1=6 | + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 三次线性遍历 | +| 空间 | O(n) | 两个辅助数组 left 和 right | + +--- +## 解法二:前缀积 + 后缀积(空间 O(1) 优化) +> 改进点:先用输出数组 `answer` 存储左边乘积,再乘上右边乘积,避免使用额外的 `right` 数组。 + +### 思路 +1. **为什么想到这种方法**:我们可以先把 `answer` 当作 `left` 数组(存储每个位置左边所有元素乘积)。然后从右向左遍历,用一个变量 `right_product` 累积右边乘积,直接乘到 `answer[i]` 上。 +2. **步骤分解**: + - 创建 `answer` 数组,长度 n。 + - 第一遍从左到右:`answer[i]` 存储 i 左边所有元素的乘积。`answer[0] = 1`,`answer[i] = answer[i-1] × nums[i-1]`。 + - 第二遍从右到左:维护一个变量 `right_product = 1`,表示当前 i 右边所有元素的乘积。 + - 更新 `answer[i] = answer[i] × right_product` + - 更新 `right_product = right_product × nums[i]` + - 返回 `answer`。 + +### 代码 +```python +class Solution: + def productExceptSelf(self, nums): + """ + 空间优化:只用输出数组存储左边乘积,再用一个变量累乘右边乘积 + """ + n = len(nums) + answer = [1] * n + + # 第一遍:计算左边乘积,存入 answer + # answer[i] = nums[0] × ... × nums[i-1] + for i in range(1, n): + answer[i] = answer[i-1] * nums[i-1] + + # 第二遍:从右向左,乘上右边乘积 + right_product = 1 # 记录当前位置右边所有元素的乘积 + for i in range(n-1, -1, -1): + # 当前位置的结果 = 左边乘积 × 右边乘积 + answer[i] = answer[i] * right_product + # 更新 right_product,为下一个位置(左边一位)准备 + right_product = right_product * nums[i] + + return answer + +# 测试 +sol = Solution() +print(sol.productExceptSelf([1,2,3,4])) # [24,12,8,6] +print(sol.productExceptSelf([-1,1,0,-3,3])) # [0,0,9,0,0] +``` + +### 手动模拟(`nums = [1,2,3,4]`) +**第一遍(左边乘积)**: +- i=0: answer[0]=1 +- i=1: answer[1]=answer[0]×nums[0]=1×1=1 +- i=2: answer[2]=answer[1]×nums[1]=1×2=2 +- i=3: answer[3]=answer[2]×nums[2]=2×3=6 +此时 answer = `[1,1,2,6]`(左边乘积) + +**第二遍(乘上右边乘积)**: +- i=3: right_product=1 → answer[3]=6×1=6,更新 right_product=1×4=4 +- i=2: right_product=4 → answer[2]=2×4=8,更新 right_product=4×3=12 +- i=1: right_product=12 → answer[1]=1×12=12,更新 right_product=12×2=24 +- i=0: right_product=24 → answer[0]=1×24=24,更新 right_product=24×1=24(用不到了) +最终 answer = `[24,12,8,6]` ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 两次线性遍历 | +| 空间 | O(1) | 只用了 `right_product` 一个变量(输出数组不计入) | + +### 边界情况 +- **包含 0**:如果数组中有 0,除了 0 所在位置外,其他位置的乘积为 0。算法能正确处理,因为乘积计算时会累乘 0。 +- **多个 0**:如果数组中有两个或以上 0,则所有位置的乘积都是 0。算法也能正确处理。 +- **负数**:乘积可能为负,算法不受影响。 +- **长度为 2**:`nums = [a,b]`,输出 `[b, a]`。第一遍后 answer=[1,a];第二遍 i=1: answer[1]=a×1=a,right=ab;i=0: answer[0]=1×ab=ab,right 更新无用;输出 [ab, a]?等等,这里错了,需要验证:实际上 answer[0] 应该是 b,不是 ab。让我重新手动算一下: + +重新手动模拟 `nums = [2,3]`: +- 第一遍:answer[0]=1,answer[1]=answer[0]×nums[0]=1×2=2 → answer=[1,2] +- 第二遍:right_product=1 + - i=1: answer[1]=2×1=2,right_product=1×3=3 + - i=0: answer[0]=1×3=3,right_product=3×2=6 +输出 `[3,2]` ✅ 正确(answer[0]=3 是 nums[1] 的值,answer[1]=2 是 nums[0] 的值) + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:两个辅助数组 | O(n) | O(n) | 思路清晰,易于理解 | 需要额外 O(n) 空间 | +| 解法二:空间优化 | O(n) | O(1) | 原地操作,满足进阶要求 | 需要理解两次遍历的作用 | + +**推荐场景**: +- 初学阶段:用解法一理解“左边乘积 × 右边乘积”的核心思想。 +- 面试阶段:**必须用解法二**,因为它满足题目要求的 O(1) 额外空间(输出数组不计),且代码简洁。这是本题的标准答案。 + +**易错提醒**: +- 第一遍遍历时,`answer[i]` 存储的是**左边**乘积,不包括 `nums[i]` 本身。 +- 第二遍遍历时,要在更新 `right_product` **之前**使用它来乘 `answer[i]`。顺序很重要。 +- 注意循环边界:第一遍从 1 到 n-1,第二遍从 n-1 到 0。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(17)41. 缺失的第一个正数.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(17)41. 缺失的第一个正数.md new file mode 100644 index 0000000..b072fd8 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(17)41. 缺失的第一个正数.md @@ -0,0 +1,220 @@ +**标签**:数组、哈希表、原地哈希、置换 + +# 缺失的第一个正数 + +## 题目理解 +- **输入**:一个未排序的整数数组 `nums`,长度 n(1 ≤ n ≤ 10⁵)。数组元素范围 -2³¹ 到 2³¹-1(即任意整数,可能为负数、0、正数)。 +- **输出**:一个整数,表示**没有出现的最小的正整数**。 +- **关键约束**: + - 时间复杂度 O(n) + - 空间复杂度 O(1)(常数级别额外空间) +- **核心思想**:答案一定在 1 到 n+1 之间(因为如果有 n 个数,最多覆盖 1~n,如果全部覆盖则答案是 n+1)。 +- **具体例子**: + - `nums = [1,2,0]` → 输出 3(1 和 2 都在,3 不在) + - `nums = [3,4,-1,1]` → 输出 2(1 在,2 不在) + - `nums = [7,8,9,11,12]` → 输出 1(1 不在) + - `nums = [1,2,3,4]` → 输出 5(1~4 都在,答案是 5) + +--- +## 解法一:使用哈希表(不满足空间要求,仅供理解) +> 原则:用集合记录所有出现过的数字,然后从 1 开始找第一个缺失的。 + +### 思路 +1. **为什么想到这种方法**:要找最小的缺失正整数,最直接的方法就是记录所有出现的数字,然后从 1 开始检查。 +2. **步骤分解**: + - 创建一个集合 `num_set`,包含数组中所有数字。 + - 从 1 开始递增,检查每个正整数是否在集合中。 + - 第一个不在集合中的正整数就是答案。 +3. **缺点**:空间复杂度 O(n),不满足题目 O(1) 的要求。 + +### 代码 +```python +class Solution: + def firstMissingPositive(self, nums): + """ + 使用集合(不满足 O(1) 空间,仅用于理解) + """ + num_set = set(nums) # 集合去重,方便快速查找 + i = 1 + while i in num_set: + i += 1 + return i + +# 测试 +sol = Solution() +print(sol.firstMissingPositive([1,2,0])) # 3 +print(sol.firstMissingPositive([3,4,-1,1])) # 2 +print(sol.firstMissingPositive([7,8,9,11,12])) # 1 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 构建集合 O(n),查找最坏 O(n) | +| 空间 | O(n) | 集合最多存储 n 个元素 | + +--- +## 解法二:原地哈希(最优解法) +> 改进点:利用数组本身作为哈希表,将每个正整数放到它正确的位置上(值 i 放到索引 i-1 的位置),然后遍历找到第一个位置不对的数字。 + +### 思路 +1. **为什么想到这种方法**:答案的范围是 1 到 n+1。我们可以把数组当作一个“哈希表”,把每个在 1~n 范围内的数字放到它应该在的位置(值 x 应该放在索引 x-1)。这样,遍历结束后,第一个 `nums[i] != i+1` 的位置,其缺失的正整数就是 `i+1`。如果所有位置都正确,则答案是 `n+1`。 +2. **步骤分解**: + - 遍历数组,对于每个元素 `nums[i]`: + - 只要 `1 <= nums[i] <= n` 且 `nums[i]` 不在正确位置上(即 `nums[i] != nums[nums[i]-1]`),就交换 `nums[i]` 和 `nums[nums[i]-1]`。 + - 注意:交换后,当前位置的新元素可能需要继续处理,所以用 `while` 循环。 + - 交换完成后,再次遍历数组: + - 如果 `nums[i] != i+1`,返回 `i+1`。 + - 如果全部正确,返回 `n+1`。 + +### 代码 +```python +class Solution: + def firstMissingPositive(self, nums): + """ + 原地哈希:将每个正整数放到正确的位置 + """ + n = len(nums) + + # 第一遍:把每个在 1~n 范围内的数字放到正确的位置 + for i in range(n): + # 注意:使用 while 而不是 if,因为交换后当前位置的新数字可能也需要处理 + # 条件:当前数字在 [1, n] 范围内,且它没有在正确的位置上 + while 1 <= nums[i] <= n and nums[i] != nums[nums[i] - 1]: + # 交换 nums[i] 和 nums[nums[i]-1] + correct_index = nums[i] - 1 + nums[i], nums[correct_index] = nums[correct_index], nums[i] + + # 第二遍:找到第一个位置不对的数字 + for i in range(n): + if nums[i] != i + 1: + return i + 1 + + # 如果 1~n 都在正确位置,缺失的是 n+1 + return n + 1 + +# 测试 +sol = Solution() +print(sol.firstMissingPositive([1,2,0])) # 3 +print(sol.firstMissingPositive([3,4,-1,1])) # 2 +print(sol.firstMissingPositive([7,8,9,11,12])) # 1 +print(sol.firstMissingPositive([1,2,3,4])) # 5 +print(sol.firstMissingPositive([2,1])) # 3 +``` + +### 手动模拟(`nums = [3,4,-1,1]`,n=4) +目标:把数字 x 放到索引 x-1 处。 + +**i=0, nums[0]=3**: +- 3 在 [1,4] 内,正确位置是索引 2(因为 3-1=2)。当前 nums[2]=-1,3 != -1,交换 → 数组变为 `[-1,4,3,1]` +- 继续 while:现在 nums[0]=-1,不在 [1,4] 内,退出循环。 + +**i=1, nums[1]=4**: +- 4 在 [1,4] 内,正确位置是索引 3(4-1=3)。当前 nums[3]=1,4 != 1,交换 → 数组变为 `[-1,1,3,4]` +- 继续 while:现在 nums[1]=1,1 在 [1,4] 内,正确位置是索引 0(1-1=0)。当前 nums[0]=-1,1 != -1,交换 → 数组变为 `[1,-1,3,4]` +- 继续 while:现在 nums[1]=-1,不在 [1,4] 内,退出循环。 + +**i=2, nums[2]=3**: +- 3 在 [1,4] 内,正确位置是索引 2(3-1=2)。当前 nums[2]=3,已经在正确位置,不交换。 + +**i=3, nums[3]=4**: +- 4 在 [1,4] 内,正确位置是索引 3(4-1=3)。当前 nums[3]=4,已经在正确位置,不交换。 + +最终数组:`[1,-1,3,4]` + +**第二遍遍历**: +- i=0: nums[0]=1 → 正确(1) +- i=1: nums[1]=-1 → 应该是 2,但实际是 -1,返回 2 ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 每个数字最多被交换一次,因为每次交换都会把一个数字放到正确位置 | +| 空间 | O(1) | 原地修改,只用了几个变量 | + +### 边界情况 +- **数组包含负数或 0**:这些数字不在 1~n 范围内,会被忽略,不影响结果。 +- **数组包含重复数字**:重复数字会多次尝试放到同一个位置,但第一次放置后,后面的重复数字会因为 `nums[i] == nums[nums[i]-1]` 而跳过。 +- **数组包含大于 n 的数字**:这些数字不需要处理,因为答案最大为 n+1。 +- **数组长度 n=1**:如果 `nums[0]=1`,返回 2;否则返回 1。 + +--- +## 解法三:标记法(另一种原地哈希思路) +> 说明:先过滤掉无关数字,然后用正负号标记数字是否存在。也是 O(n) 时间 O(1) 空间。 + +### 思路 +1. **为什么想到这种方法**:我们可以把数组本身当作标记数组。首先把负数、0 和大于 n 的数字都变成 1(或其他不影响的值),然后用下标作为“键”,用正负号表示对应数字是否存在。 +2. **步骤分解**: + - 第一遍:将数组中所有 ≤0 或 >n 的数字替换为 1(因为答案在 1~n+1 之间,这些数字不影响结果)。注意如果 n=1 需要特殊处理。 + - 第二遍:遍历数组,对于每个数字 `nums[i]`,取绝对值 `x = abs(nums[i])`。如果 `x` 在 1~n 范围内,将 `nums[x-1]` 标记为负数(表示数字 x 存在)。 + - 第三遍:遍历数组,找到第一个正数的位置,其下标 +1 就是缺失的最小正整数。如果全部是负数,则答案是 n+1。 + +### 代码 +```python +class Solution: + def firstMissingPositive(self, nums): + """ + 标记法:用正负号标记数字是否存在 + """ + n = len(nums) + + # 1. 将所有负数、0 和大于 n 的数字替换为 1 + # 注意:如果数组全是负数或 0,答案应该是 1,所以这里需要特殊处理 + has_one = False + for i in range(n): + if nums[i] == 1: + has_one = True + if nums[i] <= 0 or nums[i] > n: + nums[i] = 1 + + # 如果 1 不在数组中,答案就是 1 + if not has_one: + return 1 + + # 2. 使用正负号标记数字是否存在 + for i in range(n): + x = abs(nums[i]) # 取绝对值,因为可能已经被标记为负数 + if x <= n: + # 将索引 x-1 位置的数字标记为负数,表示数字 x 存在 + if nums[x - 1] > 0: + nums[x - 1] = -nums[x - 1] + + # 3. 找到第一个正数的位置 + for i in range(n): + if nums[i] > 0: + return i + 1 + + # 如果 1~n 都存在,答案是 n+1 + return n + 1 + +# 测试 +sol = Solution() +print(sol.firstMissingPositive([1,2,0])) # 3 +print(sol.firstMissingPositive([3,4,-1,1])) # 2 +print(sol.firstMissingPositive([7,8,9,11,12])) # 1 +print(sol.firstMissingPositive([1,2,3,4])) # 5 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 三次线性遍历 | +| 空间 | O(1) | 原地修改 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:哈希表 | O(n) | O(n) | 思路最简单 | 不满足 O(1) 空间要求 | +| 解法二:原地哈希(置换) | O(n) | O(1) | 面试标准解法,逻辑清晰 | 需要理解交换循环 | +| 解法三:标记法 | O(n) | O(1) | 另一种思路,用正负号标记 | 需要处理边界(1 是否存在) | + +**推荐场景**: +- 初学阶段:用解法一理解“从 1 开始找”的核心逻辑。 +- 面试阶段:**推荐解法二**,通过把数字交换到正确位置的方式最直接,且不需要特殊处理 1 的存在性。解法三也可以,但需要注意细节。 + +**易错提醒**: +- 解法二中,交换条件不能写成 `if` 必须用 `while`,因为交换后当前位置的新数字可能也需要调整位置。 +- 解法二中的交换条件是 `nums[i] != nums[nums[i]-1]`,而不是 `nums[i] != i+1`,因为前者能正确处理重复数字的情况。 +- 注意索引从 0 开始,所以数字 x 的正确位置是 x-1。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(18)73. 矩阵置零.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(18)73. 矩阵置零.md new file mode 100644 index 0000000..657a4bc --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(18)73. 矩阵置零.md @@ -0,0 +1,263 @@ +**标签**:矩阵、原地算法、标记法、数组 + +# 矩阵置零 + +## 题目理解 +- **输入**:一个 m 行 n 列的二维矩阵 `matrix`(1 ≤ m, n ≤ 200)。每个元素是 32 位整数。 +- **输出**:**原地修改**矩阵,如果某个元素为 0,则将其所在行和列的所有元素都设为 0。 +- **关键约束**:需要原地操作,尽可能使用常量空间。 +- **具体例子**: + - 输入 `[[1,1,1],[1,0,1],[1,1,1]]` → 输出 `[[1,0,1],[0,0,0],[1,0,1]]` + - 输入 `[[0,1,2,0],[3,4,5,2],[1,3,1,5]]` → 输出 `[[0,0,0,0],[0,4,5,0],[0,3,1,0]]` + +--- +## 解法一:使用额外数组记录(O(m+n) 空间) +> 原则:直观方法,用两个数组分别记录哪些行和哪些列需要置零。 + +### 思路 +1. **为什么想到这种方法**:如果一个位置是 0,它所在的行和列都要变成 0。我们可以先遍历一次矩阵,记录所有包含 0 的行和列,然后第二次遍历将对应的行和列置零。 +2. **步骤分解**: + - 获取矩阵的行数 m 和列数 n。 + - 创建两个布尔数组 `row_zero`(长度 m)和 `col_zero`(长度 n),初始全为 `False`。 + - 第一次遍历:如果 `matrix[i][j] == 0`,则 `row_zero[i] = True`,`col_zero[j] = True`。 + - 第二次遍历:如果 `row_zero[i] == True` 或 `col_zero[j] == True`,则将 `matrix[i][j]` 设为 0。 + +### 代码 +```python +class Solution: + def setZeroes(self, matrix): + """ + 使用 O(m+n) 额外空间记录需要清零的行和列 + """ + if not matrix: + return + + m = len(matrix) # 行数 + n = len(matrix[0]) # 列数 + + row_zero = [False] * m + col_zero = [False] * n + + # 第一次遍历:标记哪些行和列包含 0 + for i in range(m): + for j in range(n): + if matrix[i][j] == 0: + row_zero[i] = True + col_zero[j] = True + + # 第二次遍历:根据标记置零 + for i in range(m): + for j in range(n): + if row_zero[i] or col_zero[j]: + matrix[i][j] = 0 + +# 测试 +sol = Solution() +matrix1 = [[1,1,1],[1,0,1],[1,1,1]] +sol.setZeroes(matrix1) +print(matrix1) # [[1,0,1],[0,0,0],[1,0,1]] + +matrix2 = [[0,1,2,0],[3,4,5,2],[1,3,1,5]] +sol.setZeroes(matrix2) +print(matrix2) # [[0,0,0,0],[0,4,5,0],[0,3,1,0]] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m × n) | 遍历两次矩阵 | +| 空间 | O(m + n) | 两个布尔数组 | + +--- +## 解法二:使用第一行和第一列作为标记(O(1) 空间) +> 改进点:利用矩阵的第一行和第一列来存储标记信息,避免额外数组。 + +### 思路 +1. **为什么想到这种方法**:解法一用了 O(m+n) 空间来记录哪些行/列需要置零。我们可以复用矩阵的**第一行**来记录哪些列需要置零,用**第一列**来记录哪些行需要置零。但这样会覆盖原来的数据,所以需要先用两个变量单独记录第一行和第一列本身是否需要置零。 +2. **步骤分解**: + - 获取行数 m 和列数 n。 + - 用两个变量 `first_row_zero` 和 `first_col_zero` 记录第一行和第一列本身是否包含 0(因为第一行和第一列会被用作标记区,它们的原始信息需要先保存)。 + - 第一次遍历(从第 1 行第 1 列开始,即跳过第一行和第一列): + - 如果 `matrix[i][j] == 0`,则标记 `matrix[i][0] = 0`(表示第 i 行需要置零)和 `matrix[0][j] = 0`(表示第 j 列需要置零)。 + - 第二次遍历(从第 1 行第 1 列开始): + - 如果 `matrix[i][0] == 0` 或 `matrix[0][j] == 0`,则将 `matrix[i][j]` 设为 0。 + - 最后,根据 `first_row_zero` 和 `first_col_zero` 处理第一行和第一列: + - 如果 `first_row_zero` 为 True,将第一行全部设为 0。 + - 如果 `first_col_zero` 为 True,将第一列全部设为 0。 + +### 代码 +```python +class Solution: + def setZeroes(self, matrix): + """ + 使用第一行和第一列作为标记,O(1) 额外空间 + """ + if not matrix: + return + + m = len(matrix) + n = len(matrix[0]) + + # 记录第一行和第一列是否原本就有 0 + first_row_zero = False + first_col_zero = False + + # 检查第一行 + for j in range(n): + if matrix[0][j] == 0: + first_row_zero = True + break + + # 检查第一列 + for i in range(m): + if matrix[i][0] == 0: + first_col_zero = True + break + + # 用第一行和第一列作为标记区(跳过第一行第一列) + # 遍历矩阵的其余部分,如果遇到 0,就在对应的第一行和第一列做标记 + for i in range(1, m): + for j in range(1, n): + if matrix[i][j] == 0: + matrix[i][0] = 0 # 标记第 i 行需要清零 + matrix[0][j] = 0 # 标记第 j 列需要清零 + + # 根据标记,将对应的行和列置零(跳过第一行第一列) + for i in range(1, m): + for j in range(1, n): + if matrix[i][0] == 0 or matrix[0][j] == 0: + matrix[i][j] = 0 + + # 处理第一行 + if first_row_zero: + for j in range(n): + matrix[0][j] = 0 + + # 处理第一列 + if first_col_zero: + for i in range(m): + matrix[i][0] = 0 + +# 测试 +sol = Solution() +matrix1 = [[1,1,1],[1,0,1],[1,1,1]] +sol.setZeroes(matrix1) +print(matrix1) # [[1,0,1],[0,0,0],[1,0,1]] + +matrix2 = [[0,1,2,0],[3,4,5,2],[1,3,1,5]] +sol.setZeroes(matrix2) +print(matrix2) # [[0,0,0,0],[0,4,5,0],[0,3,1,0]] +``` + +### 手动模拟(`matrix = [[1,1,1],[1,0,1],[1,1,1]]`) +**初始**: +``` +[1, 1, 1] +[1, 0, 1] +[1, 1, 1] +``` + +**检查第一行**:没有 0,`first_row_zero = False` +**检查第一列**:没有 0,`first_col_zero = False` + +**标记阶段**(从 i=1, j=1 开始): +- i=1, j=1: matrix[1][1]=0 → 标记 matrix[1][0]=0, matrix[0][1]=0 +- 其他位置无 0 +标记后矩阵: +``` +[1, 0, 1] ← 第一行被标记了第 1 列(索引 1) +[0, 0, 1] +[1, 1, 1] +``` + +**置零阶段**(跳过第一行第一列): +- i=1, j=1: matrix[1][0]=0 → 置零 → `[1][1]` 已经是 0 +- i=1, j=2: matrix[1][0]=0 → 置零 → `[1][2]=0` +- i=2, j=1: matrix[0][1]=0 → 置零 → `[2][1]=0` +- i=2, j=2: 不满足条件,保持 1 +矩阵变为: +``` +[1, 0, 1] +[0, 0, 0] +[1, 0, 1] +``` + +**处理第一行**:`first_row_zero` 为 False,不变 +**处理第一列**:`first_col_zero` 为 False,不变 +最终结果 ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m × n) | 遍历矩阵多次,常数因子略大但仍是 O(mn) | +| 空间 | O(1) | 只用了两个布尔变量 | + +--- +## 解法三:更简洁的 O(1) 空间写法(用第一行记录列标记,单独变量记录第一行) +> 说明:另一种实现方式,只用一个变量记录第一行,用第一行记录列标记,第一列作为行标记的载体。 + +### 代码 +```python +class Solution: + def setZeroes(self, matrix): + """ + 更简洁的 O(1) 空间写法 + 用第一行记录哪些列需要清零,用第一列记录哪些行需要清零 + 用一个单独变量记录第一行本身是否需要清零 + """ + m, n = len(matrix), len(matrix[0]) + + # 记录第一行是否原本有 0 + first_row_zero = False + for j in range(n): + if matrix[0][j] == 0: + first_row_zero = True + break + + # 用第一行和第一列做标记(第一行记录列,第一列记录行) + for i in range(1, m): + for j in range(n): + if matrix[i][j] == 0: + matrix[i][0] = 0 # 标记第 i 行 + matrix[0][j] = 0 # 标记第 j 列 + + # 根据标记置零(跳过第一行) + for i in range(1, m): + for j in range(1, n): + if matrix[i][0] == 0 or matrix[0][j] == 0: + matrix[i][j] = 0 + + # 如果第一列有行被标记了,把第一列对应行置零 + for i in range(1, m): + if matrix[i][0] == 0: + matrix[i][0] = 0 # 实际上第一列已经可能是 0,这行是保持逻辑一致 + + # 处理第一行 + if first_row_zero: + for j in range(n): + matrix[0][j] = 0 + +# 测试 +sol = Solution() +matrix1 = [[1,1,1],[1,0,1],[1,1,1]] +sol.setZeroes(matrix1) +print(matrix1) # [[1,0,1],[0,0,0],[1,0,1]] +``` + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:额外数组 | O(m × n) | O(m + n) | 思路清晰,不易错 | 不满足进阶要求 | +| 解法二:第一行列标记 | O(m × n) | O(1) | 满足常数空间要求 | 需要处理第一行列被覆盖的问题 | +| 解法三:简洁标记 | O(m × n) | O(1) | 同上,代码稍简洁 | 逻辑仍需要仔细理解 | + +**推荐场景**: +- 初学阶段:用解法一理解标记行和列的核心思想。 +- 面试阶段:**必须用解法二或解法三**(O(1) 空间)。面试官通常期望你能想到复用第一行和第一列作为标记区。注意边界处理:第一行和第一列本身的信息要用单独变量保存。 + +**易错提醒**: +- 必须先检查第一行和第一列是否包含 0,否则标记会丢失原始信息。 +- 标记阶段要从第 1 行第 1 列开始,避免重复处理标记区本身。 +- 置零阶段也要跳过第一行第一列,最后再单独处理它们。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(19)54. 螺旋矩阵.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(19)54. 螺旋矩阵.md new file mode 100644 index 0000000..f5eeead --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(19)54. 螺旋矩阵.md @@ -0,0 +1,199 @@ +**标签**:矩阵、模拟、边界收缩、方向控制 + +# 螺旋矩阵 + +## 题目理解 +- **输入**:一个 m 行 n 列的二维矩阵 `matrix`(1 ≤ m, n ≤ 10)。矩阵元素范围 -100 到 100。 +- **输出**:一个一维列表,包含按**顺时针螺旋顺序**遍历矩阵的所有元素。 +- **遍历顺序**:从左上角 (0,0) 开始,先向右走到头,然后向下,然后向左,然后向上,然后重复(每走完一条边就收缩边界),直到所有元素都被访问。 +- **具体例子**: + - 输入 `[[1,2,3],[4,5,6],[7,8,9]]` → 输出 `[1,2,3,6,9,8,7,4,5]` + - 输入 `[[1,2,3,4],[5,6,7,8],[9,10,11,12]]` → 输出 `[1,2,3,4,8,12,11,10,9,5,6,7]` + +--- +## 解法一:边界收缩法(最直观) +> 原则:用四个变量(上下左右边界)表示当前未遍历的区域,每次按顺时针方向遍历一条边,然后收缩边界。 + +### 思路 +1. **为什么想到这种方法**:螺旋遍历的过程就像是不断剥洋葱,从外层向内层一圈一圈地遍历。我们可以用 `top`、`bottom`、`left`、`right` 四个边界来表示当前要遍历的矩形范围。 +2. **步骤分解**: + - 初始化 `top = 0`,`bottom = m-1`,`left = 0`,`right = n-1`。 + - 当 `top <= bottom` 且 `left <= right` 时循环: + - 遍历上边:从 `left` 到 `right`,将 `matrix[top][j]` 加入结果。 + - 上边界下移:`top += 1`。 + - 遍历右边:从 `top` 到 `bottom`,将 `matrix[i][right]` 加入结果。 + - 右边界左移:`right -= 1`。 + - **注意**:需要检查 `top <= bottom` 是否仍然成立,否则退出。 + - 遍历下边:从 `right` 到 `left`(逆序),将 `matrix[bottom][j]` 加入结果。 + - 下边界上移:`bottom -= 1`。 + - **注意**:需要检查 `left <= right` 是否仍然成立,否则退出。 + - 遍历左边:从 `bottom` 到 `top`(逆序),将 `matrix[i][left]` 加入结果。 + - 左边界右移:`left += 1`。 + - 返回结果列表。 + +### 代码 +```python +class Solution: + def spiralOrder(self, matrix): + """ + 边界收缩法:模拟顺时针螺旋遍历 + """ + if not matrix or not matrix[0]: + return [] + + m = len(matrix) # 行数 + n = len(matrix[0]) # 列数 + + top = 0 + bottom = m - 1 + left = 0 + right = n - 1 + + result = [] + + while top <= bottom and left <= right: + # 1. 遍历上边(从左到右) + for j in range(left, right + 1): + result.append(matrix[top][j]) + top += 1 # 上边界下移 + + # 2. 遍历右边(从上到下) + for i in range(top, bottom + 1): + result.append(matrix[i][right]) + right -= 1 # 右边界左移 + + # 3. 遍历下边(从右到左)—— 需要确保还有行 + if top <= bottom: + for j in range(right, left - 1, -1): # 逆序 + result.append(matrix[bottom][j]) + bottom -= 1 # 下边界上移 + + # 4. 遍历左边(从下到上)—— 需要确保还有列 + if left <= right: + for i in range(bottom, top - 1, -1): # 逆序 + result.append(matrix[i][left]) + left += 1 # 左边界右移 + + return result + +# 测试 +sol = Solution() +print(sol.spiralOrder([[1,2,3],[4,5,6],[7,8,9]])) # [1,2,3,6,9,8,7,4,5] +print(sol.spiralOrder([[1,2,3,4],[5,6,7,8],[9,10,11,12]])) # [1,2,3,4,8,12,11,10,9,5,6,7] +print(sol.spiralOrder([[1]])) # [1] +print(sol.spiralOrder([[1,2],[3,4]])) # [1,2,4,3] +``` + +### 手动模拟(`matrix = [[1,2,3],[4,5,6],[7,8,9]]`) +初始:top=0, bottom=2, left=0, right=2 + +**第 1 圈**: +- 上边:j=0→2 → 加入 [1,2,3];top=1 +- 右边:i=1→2 → 加入 [6,9];right=1 +- 下边:top=1 ≤ bottom=2 → j=1→0 → 加入 [8,7];bottom=1 +- 左边:left=0 ≤ right=1 → i=1→1 → 加入 [4];left=1 + +**第 2 圈**:此时 top=1, bottom=1, left=1, right=1,while 条件成立 +- 上边:j=1→1 → 加入 [5];top=2 +- 右边:i=2→1(top=2 > bottom=1),不执行(循环条件不满足) +- 下边:检查 top=2 > bottom=1,跳过 +- 左边:检查 left=1 ≤ right=1,但 top=2 > bottom=1,不执行 +退出循环,结果 = [1,2,3,6,9,8,7,4,5] ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m × n) | 每个元素被访问一次 | +| 空间 | O(1) | 除了输出数组,只用几个变量 | + +### 边界情况 +- **单行矩阵**:如 `[[1,2,3]]`,只会遍历上边,需要检查下边和左边的条件防止重复。 +- **单列矩阵**:如 `[[1],[2],[3]]`,只会遍历上边和右边,需要检查条件。 +- **单元素矩阵**:直接返回该元素。 + +--- +## 解法二:方向数组法(更通用) +> 说明:用方向数组控制移动方向,遇到边界或已访问元素就转向。适用于各种螺旋遍历场景。 + +### 思路 +1. **为什么想到这种方法**:我们可以像一只小虫子在矩阵中移动,遇到边界或已经访问过的格子就右转(顺时针改变方向),直到所有格子都被访问。 +2. **步骤分解**: + - 定义四个方向:右(0,1)、下(1,0)、左(0,-1)、上(-1,0)。 + - 用 `visited` 矩阵记录哪些位置已经被访问过(或者可以用原矩阵标记,但题目没有禁止额外空间)。 + - 初始位置 (0,0),初始方向向右。 + - 循环 m×n 次: + - 将当前位置的值加入结果。 + - 计算下一个位置 = 当前位置 + 当前方向。 + - 如果下一个位置越界或已经访问过,就改变方向(顺时针旋转 90°),重新计算下一个位置。 + - 移动到下一个位置。 + - 返回结果。 +3. **缺点**:需要 O(m×n) 的额外空间存储 visited 矩阵(或修改原矩阵)。如果要求 O(1) 空间,可以用边界法。 + +### 代码 +```python +class Solution: + def spiralOrder(self, matrix): + """ + 方向数组法:模拟移动,遇到边界就转向 + """ + if not matrix or not matrix[0]: + return [] + + m, n = len(matrix), len(matrix[0]) + # 方向顺序:右、下、左、上 + dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)] + dir_idx = 0 # 当前方向索引 + + visited = [[False] * n for _ in range(m)] + + result = [] + row, col = 0, 0 + + for _ in range(m * n): + result.append(matrix[row][col]) + visited[row][col] = True + + # 计算下一个位置 + next_row = row + dirs[dir_idx][0] + next_col = col + dirs[dir_idx][1] + + # 如果下一个位置越界或已访问,改变方向 + if (next_row < 0 or next_row >= m or + next_col < 0 or next_col >= n or + visited[next_row][next_col]): + dir_idx = (dir_idx + 1) % 4 # 顺时针旋转方向 + next_row = row + dirs[dir_idx][0] + next_col = col + dirs[dir_idx][1] + + row, col = next_row, next_col + + return result + +# 测试 +sol = Solution() +print(sol.spiralOrder([[1,2,3],[4,5,6],[7,8,9]])) # [1,2,3,6,9,8,7,4,5] +print(sol.spiralOrder([[1,2,3,4],[5,6,7,8],[9,10,11,12]])) # [1,2,3,4,8,12,11,10,9,5,6,7] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m × n) | 每个元素访问一次 | +| 空间 | O(m × n) | visited 数组(可优化为 O(1) 用边界法) | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:边界收缩 | O(m × n) | O(1) | 空间最优,逻辑清晰 | 需要仔细处理边界条件 | +| 解法二:方向数组 | O(m × n) | O(m × n) | 代码统一,易于扩展 | 需要额外空间 | + +**推荐场景**: +- 初学阶段:解法一更直观,容易理解“剥洋葱”的过程。 +- 面试阶段:**推荐解法一**,因为它空间复杂度最优(O(1)),是本题的标准答案。需要注意在遍历下边和左边之前,检查边界条件(`if top <= bottom` 和 `if left <= right`),防止单行或单列时重复遍历。 + +**易错提醒**: +- 在遍历完上边和右边后,必须先检查 `top <= bottom` 才能遍历下边,否则单行矩阵会重复遍历。 +- 同理,在遍历下边后,必须先检查 `left <= right` 才能遍历左边,否则单列矩阵会重复遍历。 +- 遍历下边和左边时,要**逆序**遍历(从右到左、从下到上)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/49.字母异位词分组.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(2)49.字母异位词分组.md similarity index 100% rename from mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/49.字母异位词分组.md rename to mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(2)49.字母异位词分组.md diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(20)48. 旋转图像.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(20)48. 旋转图像.md new file mode 100644 index 0000000..5422e17 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(20)48. 旋转图像.md @@ -0,0 +1,221 @@ +**标签**:矩阵、原地操作、数学规律、反转 + +# 旋转图像 + +## 题目理解 +- **输入**:一个 n × n 的二维矩阵 `matrix`(n 满足 1 ≤ n ≤ 20)。矩阵元素范围 -1000 到 1000。 +- **输出**:**原地修改**矩阵,将其顺时针旋转 90 度。不能使用另一个矩阵来辅助。 +- **关键点**:旋转后,原矩阵中第 i 行第 j 列的元素会移动到第 j 行第 (n-1-i) 列。公式:`new_matrix[j][n-1-i] = old_matrix[i][j]`。 +- **具体例子**: + - 输入 `[[1,2,3],[4,5,6],[7,8,9]]` → 输出 `[[7,4,1],[8,5,2],[9,6,3]]` + - 输入 `[[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]` → 输出 `[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]` + +--- +## 解法一:使用额外矩阵(不满足要求,仅供理解) +> 原则:最直观的方法,创建一个新矩阵,按旋转规则填入,再复制回去。 + +### 思路 +1. **为什么想到这种方法**:旋转 90 度有明确的公式:旋转后 `(j, n-1-i)` 位置的元素等于原矩阵 `(i, j)` 位置的元素。我们可以直接计算每个元素的新位置。 +2. **步骤分解**: + - 获取矩阵大小 n。 + - 创建新矩阵 `rotated`,大小 n×n,初始全为 0。 + - 遍历原矩阵每个位置 `(i, j)`: + - 计算旋转后的新位置:`new_i = j`,`new_j = n-1-i`。 + - 将 `matrix[i][j]` 赋值给 `rotated[new_i][new_j]`。 + - 将 `rotated` 复制回 `matrix`。 + +### 代码 +```python +class Solution: + def rotate(self, matrix): + """ + 使用额外矩阵(不满足原地要求,仅用于理解) + """ + n = len(matrix) + rotated = [[0] * n for _ in range(n)] + + for i in range(n): + for j in range(n): + # 旋转后 (i, j) 移动到 (j, n-1-i) + rotated[j][n - 1 - i] = matrix[i][j] + + # 复制回原矩阵 + for i in range(n): + for j in range(n): + matrix[i][j] = rotated[i][j] + +# 测试 +sol = Solution() +matrix1 = [[1,2,3],[4,5,6],[7,8,9]] +sol.rotate(matrix1) +print(matrix1) # [[7,4,1],[8,5,2],[9,6,3]] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n²) | 遍历所有元素两次 | +| 空间 | O(n²) | 创建了一个新矩阵 | + +--- +## 解法二:先转置,再反转每行(最优解法) +> 改进点:利用转置 + 行反转实现原地旋转,不需要额外空间。 + +### 思路 +1. **为什么想到这种方法**:观察顺时针旋转 90 度的效果,发现它等价于两步操作: + - 先对矩阵进行**转置**(行变列,列变行)。 + - 再对每一行进行**反转**(左右翻转)。 +2. **验证**(以 3×3 为例): + - 原矩阵: + ``` + [1, 2, 3] + [4, 5, 6] + [7, 8, 9] + ``` + - 转置后: + ``` + [1, 4, 7] + [2, 5, 8] + [3, 6, 9] + ``` + - 每行反转后: + ``` + [7, 4, 1] + [8, 5, 2] + [9, 6, 3] + ``` + - 与目标输出一致 ✅ +3. **步骤分解**: + - 获取矩阵大小 n。 + - **转置**:遍历 i 从 0 到 n-1,j 从 i+1 到 n-1(只遍历右上三角),交换 `matrix[i][j]` 和 `matrix[j][i]`。 + - **反转每行**:遍历每一行 i,对该行进行反转(双指针,交换对称位置)。 + +### 代码 +```python +class Solution: + def rotate(self, matrix): + """ + 原地旋转:先转置,再反转每行 + """ + n = len(matrix) + + # 第一步:转置矩阵(沿主对角线翻转) + # 只需遍历右上三角部分 + for i in range(n): + for j in range(i + 1, n): + # 交换 matrix[i][j] 和 matrix[j][i] + matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] + + # 第二步:反转每一行 + for i in range(n): + left = 0 + right = n - 1 + while left < right: + matrix[i][left], matrix[i][right] = matrix[i][right], matrix[i][left] + left += 1 + right -= 1 + +# 测试 +sol = Solution() +matrix1 = [[1,2,3],[4,5,6],[7,8,9]] +sol.rotate(matrix1) +print(matrix1) # [[7,4,1],[8,5,2],[9,6,3]] + +matrix2 = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]] +sol.rotate(matrix2) +print(matrix2) # [[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]] +``` + +### 手动模拟(n=3) +**转置**(交换右上三角): +- i=0, j=1: 交换 (0,1) 和 (1,0) → `[[1,4,3],[2,5,6],[7,8,9]]` +- i=0, j=2: 交换 (0,2) 和 (2,0) → `[[1,4,7],[2,5,6],[3,8,9]]` +- i=1, j=2: 交换 (1,2) 和 (2,1) → `[[1,4,7],[2,5,8],[3,6,9]]` +转置完成。 + +**反转每行**: +- 第 0 行:`[1,4,7]` → 反转 → `[7,4,1]` +- 第 1 行:`[2,5,8]` → 反转 → `[8,5,2]` +- 第 2 行:`[3,6,9]` → 反转 → `[9,6,3]` +最终矩阵 `[[7,4,1],[8,5,2],[9,6,3]]` ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n²) | 转置遍历一半元素 O(n²/2),反转每行 O(n × n/2) = O(n²/2) | +| 空间 | O(1) | 只用了几个变量,原地操作 | + +--- +## 解法三:直接旋转四个角(原地单层循环) +> 说明:另一种原地方法,直接处理每一圈的四个对应位置,一次性完成旋转。 + +### 思路 +1. **为什么想到这种方法**:旋转 90 度时,每个元素会移动到另一个位置,形成 4 个元素的循环(对于 n×n 矩阵,每个循环包含 4 个位置)。我们可以逐层(从外到内)处理每个循环,一次性交换这 4 个位置的值。 +2. **步骤分解**: + - 对每一层(从外到内),层数 `layer` 从 0 到 `n//2 - 1`。 + - 对于该层,遍历该层的每个起始位置 `offset`(从 0 到 `n - 2*layer - 2`): + - 四个角的位置: + - 上边:`(layer, layer + offset)` + - 右边:`(layer + offset, n-1-layer)` + - 下边:`(n-1-layer, n-1-layer - offset)` + - 左边:`(n-1-layer - offset, layer)` + - 顺时针交换这四个位置的值(用一个临时变量存储一个值,然后循环赋值)。 +3. **注意**:这种方法需要仔细处理索引,容易出错,面试中推荐解法二更简洁。 + +### 代码 +```python +class Solution: + def rotate(self, matrix): + """ + 原地旋转:逐层处理四个角 + """ + n = len(matrix) + + # 处理每一层 + for layer in range(n // 2): + first = layer + last = n - 1 - layer + + for offset in range(last - first): + # 四个角的位置 + top = matrix[first][first + offset] # 上边 + right = matrix[first + offset][last] # 右边 + bottom = matrix[last][last - offset] # 下边 + left = matrix[last - offset][first] # 左边 + + # 顺时针旋转:上 ← 左 ← 下 ← 右 ← 上 + matrix[first][first + offset] = left # 上 = 左 + matrix[first + offset][last] = top # 右 = 上 + matrix[last][last - offset] = right # 下 = 右 + matrix[last - offset][first] = bottom # 左 = 下 + +# 测试 +sol = Solution() +matrix1 = [[1,2,3],[4,5,6],[7,8,9]] +sol.rotate(matrix1) +print(matrix1) # [[7,4,1],[8,5,2],[9,6,3]] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n²) | 每个元素被处理一次 | +| 空间 | O(1) | 只用几个变量 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:额外矩阵 | O(n²) | O(n²) | 最直观,不易错 | 不满足原地要求 | +| 解法二:转置+反转 | O(n²) | O(1) | 代码简洁,面试首选 | 需要知道这个技巧 | +| 解法三:四个角交换 | O(n²) | O(1) | 直接模拟旋转过程 | 索引计算复杂,易错 | + +**推荐场景**: +- 初学阶段:用解法一理解旋转公式。 +- 面试阶段:**必须用解法二**(先转置再反转每行)。这是本题的标准答案,代码简洁且容易解释。解法三也可以,但面试官更常见解法二。 + +**易错提醒**: +- 转置时,内层循环 `j` 从 `i+1` 开始,而不是从 0 开始,否则会交换两次回到原状。 +- 反转每行时,可以用 Python 的切片语法 `matrix[i] = matrix[i][::-1]`,但为了展示原地操作,建议用双指针。 +- 如果面试官问“逆时针旋转 90 度”,可以先转置再反转每列(或先反转每行再转置)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(21)240. 搜索二维矩阵 II.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(21)240. 搜索二维矩阵 II.md new file mode 100644 index 0000000..d681de6 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(21)240. 搜索二维矩阵 II.md @@ -0,0 +1,219 @@ +**标签**:矩阵、二分查找、分治、双指针 + +# 搜索二维矩阵 II + +## 题目理解 +- **输入**:一个 m 行 n 列的矩阵 `matrix`(1 ≤ m, n ≤ 300),矩阵有特殊性质: + - 每行的元素从左到右**升序**排列。 + - 每列的元素从上到下**升序**排列。 + - 同时给定一个目标值 `target`。 +- **输出**:布尔值,表示 `target` 是否在矩阵中。 +- **关键点**:利用矩阵的排序特性,设计比暴力遍历更高效的算法。 +- **具体例子**: + - 输入矩阵和 `target = 5` → 输出 `true` + - 输入矩阵和 `target = 20` → 输出 `false` + +--- +## 解法一:暴力遍历(理解用) +> 原则:最直接的方法,遍历整个矩阵查找目标值。 + +### 思路 +1. **为什么想到这种方法**:最简单的思路就是逐个检查每个元素是否等于 target。 +2. **步骤分解**: + - 遍历每一行。 + - 遍历每一列。 + - 如果找到 target,返回 True。 + - 遍历结束未找到,返回 False。 + +### 代码 +```python +class Solution: + def searchMatrix(self, matrix, target): + """ + 暴力遍历 O(m*n) + """ + if not matrix or not matrix[0]: + return False + + m, n = len(matrix), len(matrix[0]) + + for i in range(m): + for j in range(n): + if matrix[i][j] == target: + return True + + return False + +# 测试 +sol = Solution() +matrix = [ + [1,4,7,11,15], + [2,5,8,12,19], + [3,6,9,16,22], + [10,13,14,17,24], + [18,21,23,26,30] +] +print(sol.searchMatrix(matrix, 5)) # True +print(sol.searchMatrix(matrix, 20)) # False +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m × n) | 遍历所有元素 | +| 空间 | O(1) | 只用了几个变量 | + +--- +## 解法二:逐行二分查找 +> 改进点:利用每行升序的特性,对每一行进行二分查找。 + +### 思路 +1. **为什么想到这种方法**:因为每行是升序的,可以在每一行上用二分查找,时间复杂度从 O(m×n) 降到 O(m × log n)。 +2. **步骤分解**: + - 遍历每一行。 + - 对当前行进行二分查找: + - 初始化 left = 0,right = n-1。 + - 当 left ≤ right 时,计算 mid = (left+right)//2。 + - 如果 matrix[i][mid] == target,返回 True。 + - 如果 matrix[i][mid] < target,left = mid+1。 + - 否则 right = mid-1。 + - 遍历完所有行未找到,返回 False。 + +### 代码 +```python +class Solution: + def searchMatrix(self, matrix, target): + """ + 对每一行进行二分查找 O(m * log n) + """ + if not matrix or not matrix[0]: + return False + + m, n = len(matrix), len(matrix[0]) + + for i in range(m): + # 在当前行进行二分查找 + left, right = 0, n - 1 + while left <= right: + mid = (left + right) // 2 + if matrix[i][mid] == target: + return True + elif matrix[i][mid] < target: + left = mid + 1 + else: + right = mid - 1 + + return False + +# 测试 +sol = Solution() +matrix = [ + [1,4,7,11,15], + [2,5,8,12,19], + [3,6,9,16,22], + [10,13,14,17,24], + [18,21,23,26,30] +] +print(sol.searchMatrix(matrix, 5)) # True +print(sol.searchMatrix(matrix, 20)) # False +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m × log n) | 每行二分查找 O(log n),共 m 行 | +| 空间 | O(1) | 只用了几个变量 | + +--- +## 解法三:Z 字形查找(最优解法) +> 改进点:从矩阵的右上角(或左下角)开始,利用行和列都有序的特性,每次排除一行或一列,达到 O(m+n) 的时间复杂度。 + +### 思路 +1. **为什么想到这种方法**:从右上角开始: + - 如果当前元素等于 target,直接返回 True。 + - 如果当前元素 > target,说明当前列的下方所有元素都大于 target(因为列也是升序),所以可以排除当前列,向左移动一列。 + - 如果当前元素 < target,说明当前行的左侧所有元素都小于 target(因为行是升序),所以可以排除当前行,向下移动一行。 + - 这样每次都能排除一行或一列,最多移动 m+n 次。 +2. **为什么从右上角开始**:右上角的元素是当前行的最大值、当前列的最小值,这样比较后可以明确排除一行或一列。 + - 同理,从左下角开始也可以(左下角是当前行的最小值、当前列的最大值)。 +3. **步骤分解**: + - 初始化行指针 `row = 0`,列指针 `col = n-1`(右上角)。 + - 当 `row < m` 且 `col >= 0` 时循环: + - 如果 `matrix[row][col] == target`,返回 True。 + - 如果 `matrix[row][col] > target`,说明当前列不可能有 target,`col -= 1`。 + - 如果 `matrix[row][col] < target`,说明当前行不可能有 target,`row += 1`。 + - 循环结束返回 False。 + +### 代码 +```python +class Solution: + def searchMatrix(self, matrix, target): + """ + Z 字形查找:从右上角开始,每次排除一行或一列 O(m+n) + """ + if not matrix or not matrix[0]: + return False + + m, n = len(matrix), len(matrix[0]) + + row = 0 + col = n - 1 # 从右上角开始 + + while row < m and col >= 0: + current = matrix[row][col] + if current == target: + return True + elif current > target: + # 当前值太大,排除当前列(向下更大,所以向左) + col -= 1 + else: + # 当前值太小,排除当前行(向左更小,所以向下) + row += 1 + + return False + +# 测试 +sol = Solution() +matrix = [ + [1,4,7,11,15], + [2,5,8,12,19], + [3,6,9,16,22], + [10,13,14,17,24], + [18,21,23,26,30] +] +print(sol.searchMatrix(matrix, 5)) # True +print(sol.searchMatrix(matrix, 20)) # False +print(sol.searchMatrix(matrix, 1)) # True(左上角) +print(sol.searchMatrix(matrix, 30)) # True(右下角) +print(sol.searchMatrix(matrix, 100)) # False +``` + +### 手动模拟(target = 5) +初始:row=0, col=4 → matrix[0][4]=15 > 5 → col=3 +row=0, col=3 → matrix[0][3]=11 > 5 → col=2 +row=0, col=2 → matrix[0][2]=7 > 5 → col=1 +row=0, col=1 → matrix[0][1]=4 < 5 → row=1 +row=1, col=1 → matrix[1][1]=5 == 5 → 返回 True ✅ + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(m + n) | 每次循环排除一行或一列,最多 m+n 步 | +| 空间 | O(1) | 只用了两个指针 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力遍历 | O(m × n) | O(1) | 最简单,不易错 | 效率低 | +| 解法二:逐行二分 | O(m × log n) | O(1) | 利用行有序,比暴力好 | 未充分利用列有序 | +| 解法三:Z 字形查找 | O(m + n) | O(1) | 最优,利用行和列都有序 | 需要理解从角开始的逻辑 | + +**推荐场景**: +- 初学阶段:用解法一理解问题,用解法二练习二分查找。 +- 面试阶段:**必须用解法三**(Z 字形查找),这是本题的标准答案。它能充分利用矩阵的两个排序特性,达到最优的 O(m+n) 时间复杂度。 + +**易错提醒**: +- 从右上角开始是常见做法,也可以从左下角开始,逻辑对称(`row=m-1, col=0`,比较后 `row--` 或 `col++`)。 +- 不能从左上角或右下角开始,因为比较后无法确定排除哪一行或哪一列(左上角是最小值,比 target 小可能是向下或向右)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/128.最长连续序列.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(3)128.最长连续序列.md similarity index 99% rename from mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/128.最长连续序列.md rename to mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(3)128.最长连续序列.md index 5fe498d..e642e72 100644 --- a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/128.最长连续序列.md +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(3)128.最长连续序列.md @@ -1,5 +1,5 @@ **标签**:`数组` `哈希表` - 0 + ## 题目理解 - **输入**:一个未排序的整数数组 `nums`,可能包含重复值,长度可以为 0。 diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(4)283.移动零.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(4)283.移动零.md new file mode 100644 index 0000000..2b6b4ab --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(4)283.移动零.md @@ -0,0 +1,140 @@ +**标签**:数组、双指针、原地操作、指针交换 + +# 移动零 + +## 题目理解 +- **输入**:一个整数数组 `nums`,例如 `[0, 1, 0, 3, 12]`。 +- **输出**:**原地修改**同一个数组,不返回新数组。修改后所有 `0` 移动到末尾,非零元素保持原来的前后顺序。 +- **约束条件**: + - 不能复制数组,只能在原数组上操作(空间复杂度 O(1))。 + - 数组长度至少为 1。 + - 元素可以是负数。 +- **具体例子**: + - 输入 `[0, 1, 0, 3, 12]` → 输出 `[1, 3, 12, 0, 0]` + - 输入 `[0]` → 输出 `[0]` + - 输入 `[1, 2, 3]` → 输出 `[1, 2, 3]`(没有 0,数组不变) + +--- +## 解法一:暴力法(两次遍历 + 覆盖) +> 原则:最直观的解法,让新手先理解“移动非零元素”的核心逻辑。 + +### 思路 +1. **为什么想到这种方法**:最简单的想法是,先把所有非零元素按顺序拿出来,然后把剩下的位置全部填 0。但题目要求“原地操作”,所以不能创建新数组存放非零元素。我们可以直接在原数组上做“覆盖”。 +2. **步骤分解**: + - 第一遍遍历数组,用一个索引 `write_index` 记录下一个非零元素应该存放的位置(从 0 开始)。 + - 遇到非零元素,就把它放到 `write_index` 的位置,然后 `write_index` 加 1。 + - 第一遍结束后,`write_index` 就是非零元素的个数。此时数组前 `write_index` 个位置已经是所有非零元素,并且保持了顺序。 + - 第二遍遍历,从 `write_index` 开始到数组末尾,把剩下的位置全部赋值为 `0`。 + +### 代码 +```python +class Solution: + def moveZeroes(self, nums): + """ + 原地修改 nums,将所有 0 移动到末尾 + """ + # 记录下一个非零元素应该放的位置 + write_index = 0 + + # 第一遍:把所有非零元素往前挪 + for i in range(len(nums)): # i 遍历每个位置 + if nums[i] != 0: # 遇到非零元素 + nums[write_index] = nums[i] # 放到 write_index 位置 + write_index += 1 # 指针右移 + + # 第二遍:从 write_index 开始到末尾全部填 0 + for i in range(write_index, len(nums)): + nums[i] = 0 + +# 测试示例 +sol = Solution() +nums1 = [0, 1, 0, 3, 12] +sol.moveZeroes(nums1) +print(nums1) # 输出: [1, 3, 12, 0, 0] + +nums2 = [0] +sol.moveZeroes(nums2) +print(nums2) # 输出: [0] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 遍历了两次数组,每次都是 O(n),总共 O(2n) → O(n) | +| 空间 | O(1) | 只用了 `write_index` 一个整数变量,没有复制数组 | + +### 边界情况 +- **空数组**:题目保证长度 >= 1,不处理空数组。 +- **长度为 1**:只有一个元素,如果是 0 则保持不变;如果不是 0 也保持不变(`write_index` 会变成 1,第二遍循环 `range(1,1)` 不会执行)。 +- **没有 0**:第一遍所有非零元素原地覆盖自己,`write_index` 等于数组长度,第二遍循环 `range(len, len)` 不执行,数组不变。 +- **全是 0**:第一遍一个非零元素都没有,`write_index` 保持 0,第二遍把整个数组都填 0,结果全是 0。 + +--- +## 解法二:双指针交换法(最优解法) +> 改进点:只遍历一次数组,通过交换减少赋值操作,更高效。 + +### 思路 +1. **为什么想到这种方法**:解法一需要两次遍历,第二次遍历要逐个位置写 0。我们可以用“交换”的方式,在遇到非零元素时直接把它和 0 的位置交换,这样所有 0 自然就被“挤”到末尾了。 +2. **步骤分解**: + - 维护两个指针:`slow`(指向已处理好的非零元素的下一个位置,也就是第一个 0 的位置),`fast`(遍历数组的指针)。 + - 初始时 `slow = 0`,`fast = 0`。 + - `fast` 从左到右遍历每个位置: + - 如果 `nums[fast] != 0`,说明需要把当前非零元素交换到 `slow` 的位置。 + - 交换 `nums[slow]` 和 `nums[fast]`。 + - `slow` 向右移动一位(指向下一个可能为 0 的位置)。 + - 如果 `nums[fast] == 0`,什么都不做,`fast` 继续前进。 + - 这样 `slow` 左边的元素(不含 `slow`)都是非零且保持顺序,`slow` 到 `fast` 之间(不包含 `fast`)都是 0。 +3. **手动模拟**(`nums = [0,1,0,3,12]`): + - 初始:slow=0, fast=0 → nums[0]=0,不交换,fast=1 + - slow=0, fast=1 → nums[1]=1,交换 nums[0]和nums[1] → `[1,0,0,3,12]`,slow=1,fast=2 + - slow=1, fast=2 → nums[2]=0,不交换,fast=3 + - slow=1, fast=3 → nums[3]=3,交换 nums[1]和nums[3] → `[1,3,0,0,12]`,slow=2,fast=4 + - slow=2, fast=4 → nums[4]=12,交换 nums[2]和nums[4] → `[1,3,12,0,0]`,slow=3,fast=5 结束 + +### 代码 +```python +class Solution: + def moveZeroes(self, nums): + # slow: 指向已处理好的非零元素的下一个位置(即第一个0的位置) + slow = 0 + + # fast: 遍历数组的指针 + for fast in range(len(nums)): + if nums[fast] != 0: + # 交换 slow 和 fast 位置的值 + # 如果 slow == fast,交换自己相当于没变,但为了统一逻辑也可以交换 + nums[slow], nums[fast] = nums[fast], nums[slow] + slow += 1 # slow 指向下一个可能为0的位置 + +# 测试示例 +sol = Solution() +nums1 = [0, 1, 0, 3, 12] +sol.moveZeroes(nums1) +print(nums1) # 输出: [1, 3, 12, 0, 0] + +nums2 = [0] +sol.moveZeroes(nums2) +print(nums2) # 输出: [0] + +nums3 = [1, 2, 3] +sol.moveZeroes(nums3) +print(nums3) # 输出: [1, 2, 3] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 只遍历一次数组,每个元素最多被交换一次 | +| 空间 | O(1) | 只用了两个整数指针,没有额外数组 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:两次遍历覆盖 | O(n) | O(1) | 逻辑清晰,容易理解 | 需要两次循环,如果 0 很多会做多余的赋值 | +| 解法二:双指针交换 | O(n) | O(1) | 一次遍历,交换次数少,效率更高 | 需要理解交换的含义 | + +**推荐场景**: +- 刚学编程或面试时怕手滑 → 先写法一,保证正确。 +- 追求最优解或面试进阶 → 写法二,展示对指针和原地操作的理解。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(5)11.盛最多水的容器.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(5)11.盛最多水的容器.md new file mode 100644 index 0000000..ef66a19 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(5)11.盛最多水的容器.md @@ -0,0 +1,135 @@ +**标签**:数组、双指针、贪心、贪心策略 + +# 盛最多水的容器 + +## 题目理解 +- **输入**:一个整数数组 `height`,长度 n(n >= 2)。每个元素 `height[i]` 表示在 x 轴坐标 i 处有一根垂直线,高度为 `height[i]`。 +- **输出**:一个整数,表示选择两根线(下标 i 和 j)作为容器的左右边界时,能装下的最大水量。水量 = 两根线之间的距离 × 两根线中较短的那根的高度。公式为 `min(height[i], height[j]) * (j - i)`。 +- **约束条件**: + - 不能倾斜容器,所以水量取决于较短的那根线。 + - 两根线必须不同(i != j)。 + - 数组长度最大为 10^5,因此需要 O(n) 或 O(n log n) 的解法。 +- **具体例子**: + - 输入 `[1,8,6,2,5,4,8,3,7]`,最大水量是 49(选择下标 1 的 8 和下标 8 的 7,距离为 7,min(8,7)=7,水量 7×7=49)。 + - 输入 `[1,1]`,只有两根线,水量 = min(1,1)×(1-0)=1×1=1。 + +--- +## 解法一:暴力枚举(最简单的理解方法) +> 原则:先让新手理解“什么是所有可能的组合”,再谈优化。 + +### 思路 +1. **为什么想到这种方法**:要求两根线构成容器,最直接的想法就是把所有不同的两根线组合都试一遍,计算水量,然后取最大值。 +2. **步骤分解**: + - 用两层循环:外层循环 i 从 0 到 n-2,内层循环 j 从 i+1 到 n-1。 + - 对每一对 (i, j),计算水量 = `min(height[i], height[j]) * (j - i)`。 + - 用一个变量 `max_water` 记录当前遇到的最大水量,不断更新。 + - 最后返回 `max_water`。 + +### 代码 +```python +class Solution: + def maxArea(self, height): + """ + 返回能盛最多水的容器容量 + """ + n = len(height) + max_water = 0 + + # 外层循环:左边界 i + for i in range(n - 1): + # 内层循环:右边界 j,从 i+1 开始到末尾 + for j in range(i + 1, n): + # 水量 = 较短边高度 × 宽度 + water = min(height[i], height[j]) * (j - i) + # 如果当前水量更大,更新最大值 + if water > max_water: + max_water = water + + return max_water + +# 测试示例 +sol = Solution() +print(sol.maxArea([1,8,6,2,5,4,8,3,7])) # 期望输出: 49 +print(sol.maxArea([1,1])) # 期望输出: 1 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n²) | 两层循环,总比较次数约为 n×(n-1)/2 | +| 空间 | O(1) | 只用了一个变量存储最大值 | + +### 边界情况 +- **最小长度 n=2**:只有一对组合,直接计算后返回。 +- **所有高度相等**:水量取决于宽度,最大宽度是 n-1,最大水量 = height[0] × (n-1)。 +- **高度有 0**:如果某根线高度为 0,任何包含它的容器水量都为 0。 + +--- +## 解法二:双指针法(最优解法,面试必会) +> 改进点:暴力法需要 O(n²) 时间,对于 n=10^5 会超时。双指针法只需 O(n),通过移动较短的线来逼近最优解。 + +### 思路 +1. **为什么想到这种方法**:观察水量公式 `min(h[i], h[j]) × (j-i)`。当两根线距离很大时,水量可能很大,但受限于较短的那根。一个常用的技巧是:从最宽的容器开始(i=0, j=n-1),然后尝试向内移动**较短的线**,因为移动较长的线不会让 min 变大,反而会缩小宽度,水量一定减少。 +2. **核心推理**: + - 假设当前左指针 i,右指针 j,水量 = min(h[i], h[j]) × (j-i)。 + - 如果 h[i] <= h[j](左边较短),那么移动右指针(j 向左移)不会让 min 变大(因为 min 仍受限于 h[i] 或更小),并且宽度变小,所以水量只会变小或不变。因此**移动右边没有意义**,应该移动左边(i 向右移)来寻找更高的线。 + - 同理,如果 h[i] > h[j](右边较短),应该移动右指针(j 向左移)。 +3. **步骤分解**: + - 初始化左指针 left = 0,右指针 right = n-1,max_water = 0。 + - 当 left < right 时循环: + - 计算当前水量 = min(height[left], height[right]) × (right - left)。 + - 更新 max_water 为较大值。 + - 如果 height[left] <= height[right],说明左边是短板,左指针右移(left++)。 + - 否则,右指针左移(right--)。 + - 循环结束,返回 max_water。 + +### 代码 +```python +class Solution: + def maxArea(self, height): + """ + 双指针法:从两端向中间收缩,每次移动较短的线 + """ + left = 0 # 左指针 + right = len(height) - 1 # 右指针 + max_water = 0 + + while left < right: + # 计算当前左右指针围成的容器水量 + current_water = min(height[left], height[right]) * (right - left) + # 更新最大值 + if current_water > max_water: + max_water = current_water + + # 移动较短的指针 + if height[left] <= height[right]: + left += 1 # 左边更短,左指针右移 + else: + right -= 1 # 右边更短,右指针左移 + + return max_water + +# 测试示例 +sol = Solution() +print(sol.maxArea([1,8,6,2,5,4,8,3,7])) # 输出: 49 +print(sol.maxArea([1,1])) # 输出: 1 +print(sol.maxArea([4,3,2,1,4])) # 输出: 16(选择第一个4和最后一个4,宽度4,min=4,水量16) +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 左右指针各移动最多 n 次,总共遍历一次数组 | +| 空间 | O(1) | 只用了两个指针和一个变量 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力枚举 | O(n²) | O(1) | 逻辑简单,不易出错 | n 较大时会超时(如 n=10^5) | +| 解法二:双指针 | O(n) | O(1) | 效率高,面试标准解法 | 需要理解“移动短板”的原理 | + +**推荐场景**: +- 刚开始理解问题:写一遍暴力法,确认计算水量的公式正确。 +- 实际提交或面试:必须用双指针法,因为它能通过大数据量的测试,并且展现了算法优化思维。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(6)15.三数之和.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(6)15.三数之和.md new file mode 100644 index 0000000..4de3162 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(6)15.三数之和.md @@ -0,0 +1,163 @@ +**标签**:数组、双指针、排序、去重 + +# 三数之和 + +## 题目理解 +- **输入**:一个整数数组 `nums`,长度 n(3 <= n <= 3000)。每个元素的范围是 -10^5 到 10^5。 +- **输出**:所有满足 `nums[i] + nums[j] + nums[k] == 0` 的三元组 `[nums[i], nums[j], nums[k]]`,其中 i、j、k 互不相同。返回的列表里**不能有重复的三元组**(即使顺序不同也视为重复,比如 `[-1,0,1]` 和 `[0,1,-1]` 是同一个)。 +- **约束条件**: + - 三个下标必须不同,但值可以相同(如 `[-1,-1,2]` 中两个 -1 来自不同位置)。 + - 结果中的三元组可以按任意顺序输出,但每个三元组内部通常按升序排列方便去重。 +- **具体例子**: + - 输入 `[-1,0,1,2,-1,-4]`,输出 `[[-1,-1,2],[-1,0,1]]`。 + - 输入 `[0,1,1]`,没有三元组和为 0,输出 `[]`。 + - 输入 `[0,0,0]`,只有一个三元组 `[0,0,0]`,输出 `[[0,0,0]]`。 + +--- +## 解法一:暴力枚举 + 去重(理解用) +> 原则:先让新手理解“如何穷举所有三元组”,再处理去重问题。 + +### 思路 +1. **为什么想到这种方法**:题目要求找出所有和为 0 的三元组,最直接的想法就是把所有可能的三元组都试一遍,检查它们的和是否为 0。 +2. **步骤分解**: + - 使用三重循环,i 从 0 到 n-3,j 从 i+1 到 n-2,k 从 j+1 到 n-1。 + - 对每一组 (i, j, k),检查 `nums[i]+nums[j]+nums[k]` 是否等于 0。 + - 如果等于 0,将这三个数**排序后**组成一个元组(或排序后的列表),加入一个集合(set)中。集合会自动去重。 + - 最后将集合转换成列表返回。 +3. **为什么要排序**:`[-1,0,1]` 和 `[0,1,-1]` 是同一个三元组,如果不排序,集合无法识别它们是重复的。 + +### 代码 +```python +class Solution: + def threeSum(self, nums): + """ + 返回所有和为0的三元组(不重复) + """ + n = len(nums) + result_set = set() # 用集合来去重,集合里的元素必须是不可变类型(如元组) + + # 三重循环枚举所有三元组 + for i in range(n - 2): + for j in range(i + 1, n - 1): + for k in range(j + 1, n): + if nums[i] + nums[j] + nums[k] == 0: + # 将三元组排序后转为元组,加入集合 + triplet = tuple(sorted([nums[i], nums[j], nums[k]])) + result_set.add(triplet) + + # 将集合中的元组转成列表 + return [list(t) for t in result_set] + +# 测试示例 +sol = Solution() +print(sol.threeSum([-1,0,1,2,-1,-4])) # 输出可能顺序不同: [[-1,-1,2],[-1,0,1]] +print(sol.threeSum([0,1,1])) # 输出: [] +print(sol.threeSum([0,0,0])) # 输出: [[0,0,0]] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n³) | 三重循环,总组合数约为 n³/6 | +| 空间 | O(n) | 集合最多存储 O(n²) 个三元组(实际小于 n³/6),但 n=3000 时无法运行 | + +### 边界情况 +- **n=3**:只有一组三元组,直接检查。 +- **包含重复值**:如 `[0,0,0,0]`,只有一种三元组 `[0,0,0]`,需要去重。 +- **没有解**:返回空列表。 + +--- +## 解法二:排序 + 双指针(面试标准解法) +> 改进点:将 O(n³) 降到 O(n²),通过排序后固定一个数,然后用双指针找另外两个数。 + +### 思路 +1. **为什么想到这种方法**:在两数之和问题中,如果数组有序,我们可以用双指针 O(n) 找到两数之和等于目标值。三数之和可以转化为“固定一个数,然后在剩余数组中找两数之和等于 -固定数”。 +2. **关键步骤**: + - 先对数组**排序**(升序)。排序后,重复的元素会相邻,方便去重。 + - 外层循环固定第一个数 `nums[i]`。如果 `nums[i] > 0`,由于数组已排序,后面都是正数,三数之和不可能为 0,可以直接结束循环。 + - 对于每个 i,使用双指针 left = i+1,right = n-1,在 `[i+1, n-1]` 范围内找两数之和等于 `-nums[i]`。 + - 如果三数之和等于 0,记录结果,然后**移动指针并跳过重复值**,避免产生重复的三元组。 + - 如果三数之和小于 0,说明太小,left 右移。 + - 如果三数之和大于 0,说明太大,right 左移。 +3. **去重处理**: + - 外层循环:如果 `nums[i] == nums[i-1]`,跳过(因为以这个数为第一个数的所有三元组已经找过了)。 + - 内层双指针:找到一组解后,left 右移跳过与当前 `nums[left]` 相同的值,right 左移跳过与当前 `nums[right]` 相同的值。 + +### 代码 +```python +class Solution: + def threeSum(self, nums): + """ + 排序 + 双指针 + """ + nums.sort() # 先排序,方便去重和双指针移动 + n = len(nums) + result = [] + + # 外层循环:固定第一个数 nums[i] + for i in range(n - 2): + # 去重:如果当前数和前一个数相同,跳过,避免重复三元组 + if i > 0 and nums[i] == nums[i-1]: + continue + + # 优化:如果 nums[i] > 0,后面都是正数,三数和不可能为0 + if nums[i] > 0: + break + + target = -nums[i] # 需要在 i+1 到 n-1 中找两数之和等于 target + left = i + 1 + right = n - 1 + + # 双指针查找 + while left < right: + current_sum = nums[left] + nums[right] + + if current_sum == target: + # 找到一组解 + result.append([nums[i], nums[left], nums[right]]) + + # 跳过重复的 left 值 + while left < right and nums[left] == nums[left + 1]: + left += 1 + # 跳过重复的 right 值 + while left < right and nums[right] == nums[right - 1]: + right -= 1 + + # 移动指针,继续寻找下一组可能的解 + left += 1 + right -= 1 + + elif current_sum < target: + # 和太小,左指针右移增大和 + left += 1 + else: + # 和太大,右指针左移减小和 + right -= 1 + + return result + +# 测试示例 +sol = Solution() +print(sol.threeSum([-1,0,1,2,-1,-4])) # 输出: [[-1,-1,2],[-1,0,1]] +print(sol.threeSum([0,1,1])) # 输出: [] +print(sol.threeSum([0,0,0])) # 输出: [[0,0,0]] +print(sol.threeSum([-2,0,0,2,2])) # 输出: [[-2,0,2]] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n²) | 排序 O(n log n),外层循环 O(n),内层双指针 O(n),总 O(n²) | +| 空间 | O(1) 或 O(log n) | 排序使用的额外空间取决于算法(Python 的 Timsort 是 O(n) 最坏情况,但通常忽略;如果严格要求 O(1) 可手写堆排序,面试中说明即可) | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力 + 集合去重 | O(n³) | O(n²) 最坏 | 思路简单,不易错 | n=3000 时完全不可用(约 45 亿次循环) | +| 解法二:排序 + 双指针 | O(n²) | O(1) 或 O(log n) | 面试标准解法,能通过大数据量 | 需要理解去重逻辑和双指针移动 | + +**推荐场景**: +- 初学阶段:写一遍暴力法帮助理解“枚举所有组合”,但不要提交(会超时)。 +- 面试或实际解题:必须用排序+双指针。注意去重的细节(外层和内层都要处理重复值)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(7)42.接雨水.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(7)42.接雨水.md new file mode 100644 index 0000000..57105a3 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(7)42.接雨水.md @@ -0,0 +1,208 @@ +**标签**:数组、动态规划、双指针、单调栈 + +# 接雨水 + +## 题目理解 +- **输入**:一个非负整数数组 `height`,长度 n(1 <= n <= 2*10^4)。每个元素表示柱子的高度,柱子宽度为 1。 +- **输出**:一个整数,表示下雨后能接住的雨水总量(单位与宽度一致,可以理解为“格子数”)。 +- **核心规律**:每个位置 i 上方能接多少雨水,取决于它**左边最高的柱子**和**右边最高的柱子**中较矮的那个,再减去它自己的高度。公式为:`water[i] = max(0, min(leftMax[i], rightMax[i]) - height[i])`。 +- **具体例子**: + - 输入 `[0,1,0,2,1,0,1,3,2,1,2,1]`,输出 6。 + - 输入 `[4,2,0,3,2,5]`,输出 9。 + +--- +## 解法一:按列计算(暴力法) +> 原则:从最直观的“每个位置能接多少水”入手,用最简单的方式实现。 + +### 思路 +1. **为什么想到这种方法**:雨水的总量 = 每个位置上方雨水量的总和。对于每个位置 i,找到它左边(包括 i)的最高高度,和右边(包括 i)的最高高度,取两者的较小值,减去 `height[i]`,就是该位置能接的水量(如果是负数则取 0)。 +2. **步骤分解**: + - 遍历每个位置 i(从 1 到 n-2,因为两端的柱子不可能接水)。 + - 对于每个 i,分别向左扫描找左边最高值,向右扫描找右边最高值。 + - 计算 `min(left_max, right_max) - height[i]`,累加到总水量。 +3. **注意**:这种方法虽然慢,但能帮助理解“每个位置的水量由左右最高柱子决定”的核心思想。 + +### 代码 +```python +class Solution: + def trap(self, height): + """ + 暴力法:对每个位置,分别找左边最高和右边最高 + """ + n = len(height) + if n < 3: # 少于3个柱子不可能接水 + return 0 + + total_water = 0 + + # 第一个和最后一个位置不可能接水,所以从1到n-2 + for i in range(1, n - 1): + # 找左边最高(包括当前位置) + left_max = height[i] + for j in range(i - 1, -1, -1): # 从 i-1 向左遍历到0 + if height[j] > left_max: + left_max = height[j] + + # 找右边最高(包括当前位置) + right_max = height[i] + for j in range(i + 1, n): # 从 i+1 向右遍历到 n-1 + if height[j] > right_max: + right_max = height[j] + + # 当前位置能接的水量 + water = min(left_max, right_max) - height[i] + if water > 0: + total_water += water + + return total_water + +# 测试示例 +sol = Solution() +print(sol.trap([0,1,0,2,1,0,1,3,2,1,2,1])) # 输出: 6 +print(sol.trap([4,2,0,3,2,5])) # 输出: 9 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n²) | 对于每个位置 i,最坏情况向左和向右各扫描 O(n) 次 | +| 空间 | O(1) | 只用了几个变量 | + +### 边界情况 +- **n < 3**:无法接水,直接返回 0。 +- **单调递增/递减**:如 `[1,2,3,4]`,每个位置左边或右边没有更高的柱子,接不到水。 +- **全相等**:如 `[2,2,2]`,左右最高柱子和本身一样高,接不到水。 + +--- +## 解法二:动态规划(预计算左右最大值) +> 改进点:提前用两个数组记录每个位置的左边最高值和右边最高值,避免重复扫描。 + +### 思路 +1. **为什么想到这种方法**:在暴力法中,每个位置都要向左和向右扫描,做了很多重复计算。我们可以先遍历两次数组,把每个位置的左边最大值和右边最大值提前算好存起来。 +2. **步骤分解**: + - 创建数组 `left_max`,长度 n。`left_max[i]` 表示从下标 0 到 i 的最大高度(包括 i)。 + - 从左到右填充:`left_max[0] = height[0]`,然后 `left_max[i] = max(left_max[i-1], height[i])`。 + - 创建数组 `right_max`,长度 n。`right_max[i]` 表示从下标 i 到 n-1 的最大高度(包括 i)。 + - 从右到左填充:`right_max[n-1] = height[n-1]`,然后 `right_max[i] = max(right_max[i+1], height[i])`。 + - 再次遍历每个位置 i,水量 = `min(left_max[i], right_max[i]) - height[i]`,累加正数部分。 + +### 代码 +```python +class Solution: + def trap(self, height): + """ + 动态规划:预计算每个位置的左边最高和右边最高 + """ + n = len(height) + if n < 3: + return 0 + + # left_max[i]: 从0到i(包括i)的最大高度 + left_max = [0] * n + left_max[0] = height[0] + for i in range(1, n): + left_max[i] = max(left_max[i-1], height[i]) + + # right_max[i]: 从i到n-1(包括i)的最大高度 + right_max = [0] * n + right_max[n-1] = height[n-1] + for i in range(n-2, -1, -1): + right_max[i] = max(right_max[i+1], height[i]) + + # 计算总水量 + total_water = 0 + for i in range(n): + water = min(left_max[i], right_max[i]) - height[i] + if water > 0: + total_water += water + + return total_water + +# 测试示例 +sol = Solution() +print(sol.trap([0,1,0,2,1,0,1,3,2,1,2,1])) # 输出: 6 +print(sol.trap([4,2,0,3,2,5])) # 输出: 9 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 三次线性遍历(两次预计算 + 一次累加) | +| 空间 | O(n) | 两个数组 left_max 和 right_max,各长度 n | + +--- +## 解法三:双指针法(最优解法) +> 改进点:空间复杂度从 O(n) 降到 O(1),且只需一次遍历。 + +### 思路 +1. **为什么想到这种方法**:观察动态规划解法,我们其实不需要同时知道左右两边的所有最大值。当我们从两边向中间移动时,可以实时维护左边当前的最大值和右边当前的最大值。哪个小,就处理哪一边的水量。 +2. **核心逻辑**: + - 初始化左指针 left = 0,右指针 right = n-1。 + - 维护 left_max(从左边扫过来的最大值)和 right_max(从右边扫过来的最大值)。 + - 如果 `height[left] < height[right]`,说明 left 位置的水量由 left_max 决定(因为右边有更高的柱子挡着)。计算 left 位置的水量,然后 left 右移。 + - 否则,right 位置的水量由 right_max 决定,计算后 right 左移。 +3. **为什么这样可行**: + - 对于 left 指针,`left_max` 是它左边(包括自己)的最大值,`right_max` 是右边(包括自己)的最大值。但我们不知道 `right_max` 是不是整个右边的最大值?实际上,因为 `height[left] < height[right]`,而 `right_max` 至少是 `height[right]`,所以 `right_max >= height[right] > height[left]`。因此左边的 `left_max` 一定小于等于 `right_max`,所以 `min(left_max, right_max) = left_max`,可以直接计算。 + +### 代码 +```python +class Solution: + def trap(self, height): + """ + 双指针法:一次遍历,空间O(1) + """ + n = len(height) + if n < 3: + return 0 + + left = 0 + right = n - 1 + left_max = height[left] # 左边扫过的最大值 + right_max = height[right] # 右边扫过的最大值 + total_water = 0 + + while left < right: + # 如果左边柱子比右边矮,处理左边 + if height[left] < height[right]: + # 更新左边最大值 + if height[left] > left_max: + left_max = height[left] + else: + # 当前位置能接的水量 = left_max - height[left] + total_water += left_max - height[left] + left += 1 + else: + # 否则处理右边 + if height[right] > right_max: + right_max = height[right] + else: + total_water += right_max - height[right] + right -= 1 + + return total_water + +# 测试示例 +sol = Solution() +print(sol.trap([0,1,0,2,1,0,1,3,2,1,2,1])) # 输出: 6 +print(sol.trap([4,2,0,3,2,5])) # 输出: 9 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 一次遍历,每个元素处理一次 | +| 空间 | O(1) | 只用了几个指针和变量 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力按列 | O(n²) | O(1) | 思路直观,容易理解 | n 较大时超时 | +| 解法二:动态规划 | O(n) | O(n) | 时间优,空间可接受 | 需要两个辅助数组 | +| 解法三:双指针 | O(n) | O(1) | 最优,时间空间俱佳 | 需要理解“矮边决定水量”的推理 | + +**推荐场景**: +- 初学阶段:先写暴力法,理解“每个位置水量由左右最高决定”。 +- 进阶阶段:掌握动态规划,能写出 O(n) 时间、O(n) 空间的解法。 +- 面试阶段:必须能写出双指针法,展现对空间优化的追求。如果面试官要求逐步优化,就按暴力 → DP → 双指针的顺序讲解。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(8)3.无重复字符的最长子串.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(8)3.无重复字符的最长子串.md new file mode 100644 index 0000000..aff103a --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(8)3.无重复字符的最长子串.md @@ -0,0 +1,153 @@ +**标签**:字符串、滑动窗口、哈希表、双指针 + +# 无重复字符的最长子串 + +## 题目理解 +- **输入**:一个字符串 `s`,长度可以是 0 到 5×10⁴。字符串可能包含字母、数字、符号和空格。 +- **输出**:一个整数,表示最长的不包含重复字符的**子串**的长度。 +- **关键概念区分**: + - **子串**:原字符串中连续的一段。例如 `"abc"` 是 `"abcabcbb"` 的子串,但 `"acb"` 不是(不连续)。 + - **子序列**:可以不连续,本题要求的是子串。 +- **具体例子**: + - `s = "abcabcbb"` → 最长无重复子串是 `"abc"` 或 `"bca"` 或 `"cab"`,长度 3。 + - `s = "bbbbb"` → 最长无重复子串是 `"b"`,长度 1。 + - `s = "pwwkew"` → 最长无重复子串是 `"wke"`,长度 3(注意 `"pwke"` 不是子串,因为不连续)。 + +--- +## 解法一:暴力枚举(理解用) +> 原则:最直观的方法,枚举所有可能的子串,检查每个子串是否有重复字符。 + +### 思路 +1. **为什么想到这种方法**:题目要求“最长无重复子串”,最直接的想法就是把所有子串都找出来,检查哪些没有重复字符,然后记录最大长度。 +2. **步骤分解**: + - 用两层循环枚举所有子串:外层循环 i 表示子串起点,内层循环 j 从 i 到末尾。 + - 对于每个子串 `s[i:j+1]`,检查其中是否有重复字符。 + - 如何检查重复?可以用一个集合(set),遍历子串中的每个字符,如果字符已经在集合中出现,说明有重复;否则加入集合。 + - 如果当前子串没有重复,就用它的长度更新最大值。 +3. **注意**:这种方法虽然直观,但效率很低,字符串长度较大时会超时。 + +### 代码 +```python +class Solution: + def lengthOfLongestSubstring(self, s): + """ + 暴力枚举所有子串 + """ + n = len(s) + max_len = 0 + + # 枚举所有起点 + for i in range(n): + # 枚举所有终点(从 i 到末尾) + for j in range(i, n): + # 检查子串 s[i:j+1] 是否有重复字符 + char_set = set() # 创建空集合,用于存放已经遇到的字符 + has_duplicate = False + for k in range(i, j + 1): # 遍历子串中的每个字符 + if s[k] in char_set: # 如果字符已经在集合中 + has_duplicate = True + break + char_set.add(s[k]) # 否则加入集合 + + # 如果没有重复,更新最大长度 + if not has_duplicate: + max_len = max(max_len, j - i + 1) + + return max_len + +# 测试 +sol = Solution() +print(sol.lengthOfLongestSubstring("abcabcbb")) # 3 +print(sol.lengthOfLongestSubstring("bbbbb")) # 1 +print(sol.lengthOfLongestSubstring("pwwkew")) # 3 +print(sol.lengthOfLongestSubstring("")) # 0 +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n³) | 外层循环 O(n),内层循环 O(n),检查重复又需要 O(n),总 O(n³) | +| 空间 | O(min(n, m)) | 集合最多存储子串长度个字符,m 是字符集大小(本题最多 128 种 ASCII 字符) | + +### 边界情况 +- **空字符串**:长度为 0,返回 0。 +- **全相同字符**:如 `"aaaa"`,最长子串长度为 1。 +- **全不同字符**:如 `"abcd"`,最长子串长度为 n。 + +--- +## 解法二:滑动窗口(最优解法) +> 改进点:将 O(n³) 降到 O(n),通过维护一个窗口,保证窗口内字符不重复,窗口右边界每次右移,左边界根据需要右移。 + +### 思路 +1. **为什么想到这种方法**:暴力法中,当子串 `s[i:j+1]` 发现重复字符时,我们其实可以知道重复字符的位置,然后跳过一些不必要的检查。例如 `"abcabc"`,当 i=0, j=3 时发现 `'a'` 重复(位置 0 和 3),那么以 i=0 为起点的子串再往后扩展都会包含重复的 `'a'`,所以我们可以直接移动起点到重复字符的下一个位置(即 i=1)。 +2. **核心思想**:维护一个窗口 `[left, right]`,保证窗口内的字符都不重复。每次将右指针 `right` 向右移动一步,如果新加入的字符在窗口内已经存在,就移动左指针 `left` 到重复字符的下一个位置,直到窗口内没有重复字符。 +3. **如何快速找到重复字符的位置**:使用哈希表(字典)记录每个字符最近一次出现的位置。当遇到重复字符时,左指针可以直接跳到该字符上次出现位置 + 1。 +4. **步骤分解**: + - 初始化 `left = 0`,`max_len = 0`。 + - 创建字典 `char_index`,用于存储每个字符最近一次出现的下标。 + - 遍历字符串,`right` 从 0 到 n-1: + - 如果 `s[right]` 已经在字典中,并且它的上一次出现位置 `>= left`(说明在当前窗口内),就把 `left` 移动到 `char_index[s[right]] + 1`。 + - 更新 `char_index[s[right]] = right`。 + - 计算当前窗口长度 `right - left + 1`,更新 `max_len`。 + - 返回 `max_len`。 + +### 代码 +```python +class Solution: + def lengthOfLongestSubstring(self, s): + """ + 滑动窗口 + 哈希表 + """ + n = len(s) + if n == 0: + return 0 + + char_index = {} # 字典:字符 -> 它最近一次出现的下标 + left = 0 # 窗口左边界 + max_len = 0 + + # right 是窗口右边界 + for right in range(n): + current_char = s[right] + + # 如果当前字符已经在窗口内出现过(上次出现位置 >= left) + if current_char in char_index and char_index[current_char] >= left: + # 左指针跳到重复字符的下一个位置 + left = char_index[current_char] + 1 + + # 更新当前字符的最新位置 + char_index[current_char] = right + + # 计算当前窗口长度,更新最大值 + current_len = right - left + 1 + if current_len > max_len: + max_len = current_len + + return max_len + +# 测试 +sol = Solution() +print(sol.lengthOfLongestSubstring("abcabcbb")) # 3 +print(sol.lengthOfLongestSubstring("bbbbb")) # 1 +print(sol.lengthOfLongestSubstring("pwwkew")) # 3 +print(sol.lengthOfLongestSubstring("")) # 0 +print(sol.lengthOfLongestSubstring("abba")) # 2(子串 "ab" 或 "ba") +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 每个字符最多被左指针和右指针各访问一次 | +| 空间 | O(min(n, m)) | 字典最多存储 n 个键值对,m 是字符集大小(本题最多 128) | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力枚举 | O(n³) | O(min(n, m)) | 思路最直观,容易理解 | 效率极低,无法通过大数据 | +| 解法二:滑动窗口 | O(n) | O(min(n, m)) | 时间最优,空间小,面试标准解法 | 需要理解窗口移动的时机 | + +**推荐场景**: +- 初学阶段:写一遍暴力法理解“什么是子串”和“如何检查重复”,但不要提交。 +- 面试阶段:必须用滑动窗口解法。注意处理左指针移动的条件(`char_index[current_char] >= left` 而不是简单的 `in` 判断,因为字符可能出现在窗口左边)。经典易错例子是 `"abba"`,如果只用 `in` 判断而不检查位置,会导致错误。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(9)438.找出字符串中的所有字母异位词.md b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(9)438.找出字符串中的所有字母异位词.md new file mode 100644 index 0000000..74867e3 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/算法与数据结构/LeetCode热题100/(9)438.找出字符串中的所有字母异位词.md @@ -0,0 +1,253 @@ +**标签**:字符串、滑动窗口、哈希表、字母计数 + +# 找到字符串中所有字母异位词 + +## 题目理解 +- **输入**:两个字符串 `s` 和 `p`,长度范围 1 到 3×10⁴。两个字符串都只包含**小写字母**(a-z)。 +- **输出**:一个列表,包含 `s` 中所有是 `p` 的异位词的子串的起始索引。顺序不限。 +- **什么是异位词**:两个字符串包含的字符种类和数量完全相同,只是顺序可以不同。例如 `"abc"` 和 `"cba"` 互为异位词。 +- **具体例子**: + - `s = "cbaebabacd"`, `p = "abc"` → 输出 `[0, 6]`(子串 `"cba"` 和 `"bac"` 都是 `"abc"` 的异位词)。 + - `s = "abab"`, `p = "ab"` → 输出 `[0, 1, 2]`(子串 `"ab"`、`"ba"`、`"ab"` 都是 `"ab"` 的异位词)。 + +--- +## 解法一:暴力枚举 + 排序比较(理解用) +> 原则:最直接的方法,枚举所有长度等于 `len(p)` 的子串,排序后与排序后的 `p` 比较。 +我喜欢你 +### 思路 +1. **为什么想到这种方法**:判断两个字符串是否为异位词,一个简单方法是分别排序,如果排序后相同,说明它们包含相同字符且数量相同。 +2. **步骤分解**: + - 获取 `p` 的长度 `m`。 + - 如果 `len(s) < m`,直接返回空列表(因为 s 中不可能有长度 m 的子串)。 + - 遍历 `s` 中所有起始索引 `i`(从 0 到 `len(s)-m`): + - 取出子串 `s[i:i+m]`。 + - 将子串和 `p` 分别转换为字符列表,排序,然后比较。 + - 如果相等,说明是异位词,将 `i` 加入结果列表。 + +### 代码 +```python +class Solution: + def findAnagrams(self, s, p): + """ + 暴力法:枚举所有子串,排序后比较 + """ + m = len(p) + n = len(s) + if n < m: + return [] + + # 将 p 排序后保存,用于比较 + sorted_p = sorted(p) # sorted() 返回字符列表,如 ['a','b','c'] + result = [] + + # 枚举所有长度为 m 的子串的起始位置 + for i in range(n - m + 1): + # 取出子串 + sub = s[i:i+m] + # 排序子串 + sorted_sub = sorted(sub) + # 比较是否相同 + if sorted_sub == sorted_p: + result.append(i) + + return result + +# 测试 +sol = Solution() +print(sol.findAnagrams("cbaebabacd", "abc")) # [0, 6] +print(sol.findAnagrams("abab", "ab")) # [0, 1, 2] +print(sol.findAnagrams("a", "a")) # [0] +print(sol.findAnagrams("a", "ab")) # [] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n × m log m) | 有 O(n) 个子串,每个子串排序 O(m log m) | +| 空间 | O(m) | 存储排序后的子串和 p | + +### 边界情况 +- **s 长度 < p 长度**:返回空列表。 +- **p 长度为 1**:找所有等于 p 的单个字符的位置。 +- **全相同字符**:如 `s = "aaaa", p = "aa"`,所有长度为 2 的子串都是异位词。 + +--- +## 解法二:滑动窗口 + 固定长度(计数法) +> 改进点:用字符计数代替排序,将 O(m log m) 降为 O(1)。因为只有 26 个小写字母,可以用长度为 26 的数组记录每个字符出现次数。 + +### 思路 +1. **为什么想到这种方法**:判断异位词不需要排序,只需要知道每个字母出现的次数是否相同。用两个长度为 26 的数组分别记录 p 和当前窗口的字母频率,比较两个数组是否相等即可。 +2. **步骤分解**: + - 创建数组 `p_count` 长度 26,统计 `p` 中每个字母的出现次数。 + - 创建数组 `window_count` 长度 26,统计当前窗口中字母的出现次数。 + - 先处理第一个窗口(`s[0:m]`),将其中字母的计数填入 `window_count`。 + - 检查 `window_count` 是否等于 `p_count`,如果是,将 0 加入结果。 + - 然后滑动窗口:每次右边界右移一位(加入一个新字符),左边界右移一位(移出一个旧字符),更新 `window_count`。 + - 每滑动一次,比较两个数组是否相等,如果相等,将当前窗口的起始索引加入结果。 +3. **如何比较两个长度为 26 的数组**:可以直接用 `==` 比较,因为 Python 列表比较是按元素逐个比较的。 + +### 代码 +```python +class Solution: + def findAnagrams(self, s, p): + """ + 滑动窗口 + 固定长度 + 字母计数 + """ + m = len(p) + n = len(s) + if n < m: + return [] + + # 因为只有小写字母,用长度为 26 的数组记录每个字母出现次数 + # ord('a') 返回字母 a 的 ASCII 码,ord('b') = ord('a') + 1,以此类推 + p_count = [0] * 26 + window_count = [0] * 26 + + # 统计 p 中每个字母的出现次数 + for ch in p: + index = ord(ch) - ord('a') # 将字母映射到 0~25 + p_count[index] += 1 + + # 初始化第一个窗口(s[0:m]) + for i in range(m): + index = ord(s[i]) - ord('a') + window_count[index] += 1 + + result = [] + # 检查第一个窗口 + if window_count == p_count: + result.append(0) + + # 滑动窗口:从索引 m 开始遍历 s 的剩余字符 + for i in range(m, n): + # 加入新字符(窗口右边界右移) + new_char_index = ord(s[i]) - ord('a') + window_count[new_char_index] += 1 + + # 移出旧字符(窗口左边界右移,移除的是 s[i-m]) + old_char_index = ord(s[i - m]) - ord('a') + window_count[old_char_index] -= 1 + + # 检查当前窗口是否与 p 的计数相同 + if window_count == p_count: + result.append(i - m + 1) # 当前窗口起始索引 = i - m + 1 + + return result + +# 测试 +sol = Solution() +print(sol.findAnagrams("cbaebabacd", "abc")) # [0, 6] +print(sol.findAnagrams("abab", "ab")) # [0, 1, 2] +print(sol.findAnagrams("a", "a")) # [0] +print(sol.findAnagrams("a", "ab")) # [] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 遍历 s 一次,每次比较两个长度为 26 的数组是 O(26)=O(1) | +| 空间 | O(1) | 两个固定长度 26 的数组,空间恒定 | + +--- +## 解法三:滑动窗口 + 计数差异优化(进阶) +> 改进点:不需要每次比较整个数组,用一个变量 `diff` 记录当前窗口与 p 的差异字符数,当 diff = 0 时说明匹配。 + +### 思路 +1. **为什么想到这种方法**:每次比较两个长度为 26 的数组虽然已经是 O(1),但常数 26 在大量滑动时仍有开销。可以用一个变量记录“有多少个字母的计数不同”,当这个变量为 0 时说明匹配。 +2. **步骤分解**: + - 先计算 p 的计数 `p_count`。 + - 初始化窗口,对于窗口中的每个字符,让 `p_count` 中对应计数减 1(相当于用 p_count 减去窗口计数)。 + - 统计 `p_count` 中有多少个非零值,记为 `diff`。`diff` 表示当前窗口与 p 有多少个字母的计数不同。 + - 如果 `diff == 0`,说明匹配,记录起始索引。 + - 滑动窗口时: + - 移出左边字符:该字符的计数加 1(因为 p_count 原本减了窗口计数,移出后要恢复)。加之前如果是 0,说明原本这个字母计数匹配,移出后变为 1,`diff` 增加 1;加之后如果变为 0,说明原本不匹配,现在变匹配了,`diff` 减少 1。 + - 加入右边字符:该字符的计数减 1。减之前如果是 0,说明原本匹配,减后变为 -1,`diff` 增加 1;减之后如果变为 0,说明原本不匹配,现在匹配了,`diff` 减少 1。 + - 每次更新后检查 `diff == 0`,记录起始索引。 + +### 代码 +```python +class Solution: + def findAnagrams(self, s, p): + """ + 滑动窗口 + 差异计数优化 + """ + m = len(p) + n = len(s) + if n < m: + return [] + + # count 数组:初始为 p 的计数,然后减去窗口中的计数 + # 最终 count[ch] == 0 表示 ch 在窗口中的数量与 p 中相同 + count = [0] * 26 + + # 统计 p 中每个字母的出现次数 + for ch in p: + count[ord(ch) - ord('a')] += 1 + + # 初始化第一个窗口:减去窗口中字母的计数 + for i in range(m): + count[ord(s[i]) - ord('a')] -= 1 + + # 统计有多少个字母的计数不为 0(即与 p 的数量不同) + diff = 0 + for c in count: + if c != 0: + diff += 1 + + result = [] + if diff == 0: + result.append(0) + + # 滑动窗口 + for i in range(m, n): + # 移出左边字符 s[i-m] + left_char = ord(s[i - m]) - ord('a') + if count[left_char] == 0: + # 原本匹配,移出后不匹配,diff 增加 + diff += 1 + count[left_char] += 1 # 移出字符,count 增加(因为之前减过) + if count[left_char] == 0: + # 移出后变匹配,diff 减少 + diff -= 1 + + # 加入右边字符 s[i] + right_char = ord(s[i]) - ord('a') + if count[right_char] == 0: + # 原本匹配,加入后不匹配,diff 增加 + diff += 1 + count[right_char] -= 1 # 加入字符,count 减少 + if count[right_char] == 0: + # 加入后变匹配,diff 减少 + diff -= 1 + + # 检查是否完全匹配 + if diff == 0: + result.append(i - m + 1) + + return result + +# 测试 +sol = Solution() +print(sol.findAnagrams("cbaebabacd", "abc")) # [0, 6] +print(sol.findAnagrams("abab", "ab")) # [0, 1, 2] +``` + +### 复杂度分析 +| 维度 | 复杂度 | 说明 | +|------|--------|------| +| 时间 | O(n) | 遍历一次,每次操作 O(1) | +| 空间 | O(1) | 固定长度 26 的数组 | + +--- +## 解法对比总结 + +| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | +|------|-----------|-----------|------|------| +| 解法一:暴力+排序 | O(n × m log m) | O(m) | 思路最简单 | 效率低,无法通过大数据 | +| 解法二:滑动窗口+计数 | O(n) | O(1) | 时间空间均优,易实现 | 每次比较整个数组(常数26) | +| 解法三:滑动窗口+差异 | O(n) | O(1) | 最快,常数最小 | 代码稍复杂,需要理解 diff 变化逻辑 | + +**推荐场景**: +- 初学阶段:理解暴力法,知道什么是异位词。 +- 面试准备:解法二是最佳平衡点,代码清晰且效率高,面试中首选。 +- 追求极致性能:解法三适合对常数有严格要求的场景,但通常解法二已经足够。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/编程语言/Python/Python数组,元组,集合,字典数据结构对比.md b/mengyanote-backend/data/mengyanote/编程语言/Python/Python数组,元组,集合,字典数据结构对比.md new file mode 100644 index 0000000..1d36e96 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/编程语言/Python/Python数组,元组,集合,字典数据结构对比.md @@ -0,0 +1,68 @@ + +| 数据结构 | 英文名 | 可变性 | 有序性 | 元素唯一性 | 访问方式 | +|---------|--------|--------|--------|-----------|---------| +| **列表/数组** | `list` | ✅ 可变 | ✅ 有序 | ❌ 可重复 | 整数索引 | +| **元组** | `tuple` | ❌ 不可变 | ✅ 有序 | ❌ 可重复 | 整数索引 | +| **集合** | `set` | ✅ 可变 | ❌ 无序 | ✅ 唯一 | 无索引,迭代 | +| **字典** | `dict` | ✅ 可变 | ✅ 有序(3.7+) | ❌ key唯一 | key 映射 | + +--- +### 1. 列表(list)— 最常用 +```python +lst = [1, 2, 3, 2] # 方括号 [] +lst.append(4) # 可增删改 +lst[0] # 下标访问 +``` +- 可变、有序、可重读 +- 存同类或混合类型数据都可以,适合 **顺序遍历、堆栈、队列** +### 2. 元组(tuple)— 只读列表 +```python +t = (1, 2, 3, 2) # 圆括号 () +t[0] # 可读取 +t[0] = 10 # ❌ 报错,不可修改 +``` +- 不可变,一旦创建不能增删改 +- 可哈希,所以能当 **字典的 key** 或放进集合 +- 适合 **固定配置、函数多返回值**、**拆包赋值** +### 3. 集合(set)— 去重 + 集合运算 +```python +s = {1, 2, 3, 2} # 花括号 {},结果 {1, 2, 3} +s.add(4) +s1 = {1, 2}; s2 = {2, 3} +s1 & s2 # 交集 {2} +s1 | s2 # 并集 {1, 2, 3} +s1 - s2 # 差集 {1} +``` +- 可变、无序、元素唯一(自动去重) +- 底层哈希表 → 查找 `x in s` 平均 O(1),比列表快得多 +- 不能下标访问,只能遍历 +- 元素必须是**可哈希**类型(数字、字符串、元组,不能是列表/字典本身) +### 4. 字典(dict)— key-value 映射 +```python +d = {"name": "萌小芽", "age": 3} +d["name"] # "萌小芽" +d["role"] = "助手" # 新增/修改 +d.keys() d.values() d.items() +``` +- 可变,Python 3.7+ **保留插入顺序** +- key 必须可哈希(字符串、数字、元组),value 任意 +- 查找 `d[key]` O(1),适合 **快速查表、JSON 数据、属性容器** +--- +### 进阶数据结构 + +| 结构 | 说明 | +| ---------------------------------- | --------------------------------------- | +| **frozenset** `frozenset({1,2,3})` | 不可变集合,可作为字典 key | +| **collections.deque** | 双端队列,两端插入/弹出 O(1) | +| **collections.Counter** | 计数型字典,`Counter("aab") → {'a':2, 'b':1}` | +| **collections.defaultdict** | 自动缺省值的字典 | +| **collections.OrderedDict** | 有序字典(3.7+ 普通 dict 已有序,主要用于兼容旧版) | +| **array.array** | 类型化数组,比 list 省内存(存同类型数值) | +| **heapq** | 堆(优先队列),`heapq.heappush/pop` | +| **bisect** | 二分查找/插入,适合有序列表 | + +--- +### 总结记忆口诀 +> **列表可变序可重,元组只读不能动** +> **集合无序且唯一,哈希查重速度快** +> **字典键值映射快,源码到处用它来** diff --git a/mengyanote-backend/data/mengyanote/西南石油大学/网络互连ensp常用命令总结.md b/mengyanote-backend/data/mengyanote/西南石油大学/网络互连ensp常用命令总结.md new file mode 100644 index 0000000..d4b2d79 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/西南石油大学/网络互连ensp常用命令总结.md @@ -0,0 +1,296 @@ + +## 一、系统视图与基本操作 + +### 1.1 视图层级切换 +``` + system-view # 用户视图 → 系统视图 +[Huawei] interface GigabitEthernet0/0/0 # 系统视图 → 接口视图 +[Huawei] ospf 1 # 系统视图 → OSPF协议视图 +[Huawei] vlan 10 # 系统视图 → VLAN视图 +[Huawei-ospf-1] quit # 退回上一级 +[Huawei-ospf-1] return # 直接退回用户视图 +``` + +| 视图 | 提示符 | 说明 | +| ------- | ------------------------------- | --------------------- | +| 用户视图 | `` | 查看信息、调试,不可修改配置 | +| 系统视图 | `[Huawei]` | 全局配置,`system-view` 进入 | +| 接口视图 | `[Huawei-GigabitEthernet0/0/0]` | 端口相关配置 | +| 协议视图 | `[Huawei-ospf-1]` | 路由协议配置 | +| VLAN 视图 | `[Huawei-vlan10]` | VLAN 配置 | +| ACL 视图 | `[Huawei-acl-basic-2000]` | ACL 规则 | + +### 1.2 基础系统命令 +``` + sysname R1 # 修改设备名称 + display version # 查看VRP版本 + display current-configuration # 查看当前配置(可简写 disp cur) + display saved-configuration # 查看保存的配置 + save # 保存配置 + reboot # 重启设备 + reset saved-configuration # 清除已保存的配置 + undo interface GigabitEthernet0/0/0 shutdown # 取消端口关闭 +``` + +### 1.3 命令编辑快捷键 +| 按键 | 作用 | +|------|------| +| `Tab` | 自动补全命令 | +| `?` | 显示当前模式下可用命令或参数提示 | +| `↑ / ↓` | 浏览历史命令 | +| `Ctrl+Z` | 返回到用户视图 | +| `Ctrl+C` | 中断当前命令 | +| `undo` | 取消某条配置(华为特色) | + +--- + +## 二、接口配置 + +### 2.1 接口基本配置 +``` +[Huawei] interface GigabitEthernet0/0/0 # 进入接口 +[Huawei-GigabitEthernet0/0/0] ip address 192.168.1.1 255.255.255.0 # 配置IP +[Huawei-GigabitEthernet0/0/0] description To_R2 # 接口描述 +[Huawei-GigabitEthernet0/0/0] shutdown # 关闭接口 +[Huawei-GigabitEthernet0/0/0] undo shutdown # 启用接口 +[Huawei-GigabitEthernet0/0/0] speed 100 # 配置速率 +[Huawei-GigabitEthernet0/0/0] duplex full # 配置双工模式(full/half/auto) +[Huawei-GigabitEthernet0/0/0] display this # 查看当前视图配置 +``` + +### 2.2 Loopback 接口(模拟路由器自身地址) +``` +[Huawei] interface LoopBack 0 +[Huawei-LoopBack0] ip address 10.0.0.1 255.255.255.255 +``` + +### 2.3 子接口(单臂路由) +``` +[Huawei] interface GigabitEthernet0/0/0.10 +[Huawei-GigabitEthernet0/0/0.10] dot1q termination vid 10 +[Huawei-GigabitEthernet0/0/0.10] ip address 192.168.10.1 255.255.255.0 +[Huawei-GigabitEthernet0/0/0.10] arp broadcast enable +``` + +--- + +## 三、VLAN 配置(交换机) + +### 3.1 创建 VLAN 并划分端口 +``` +[Huawei] vlan batch 10 20 30 40 # 批量创建 VLAN +[Huawei] vlan 10 +[Huawei-vlan10] name Sales # VLAN 命名 + +# Access 端口(连接终端) +[Huawei] interface GigabitEthernet0/0/1 +[Huawei-GigabitEthernet0/0/1] port link-type access +[Huawei-GigabitEthernet0/0/1] port default vlan 10 + +# Trunk 端口(连接交换机) +[Huawei] interface GigabitEthernet0/0/24 +[Huawei-GigabitEthernet0/0/24] port link-type trunk +[Huawei-GigabitEthernet0/0/24] port trunk allow-pass vlan 10 20 30 +[Huawei-GigabitEthernet0/0/24] port trunk allow-pass vlan all # 允许所有VLAN + +# Hybrid 端口(特殊混合模式,华为特有) +[Huawei-GigabitEthernet0/0/1] port link-type hybrid +[Huawei-GigabitEthernet0/0/1] port hybrid tagged vlan 10 20 +[Huawei-GigabitEthernet0/0/1] port hybrid untagged vlan 1 +``` + +### 3.2 VLAN 间路由(三层交换) +``` +[Huawei] interface Vlanif 10 +[Huawei-Vlanif10] ip address 192.168.10.254 255.255.255.0 +[Huawei] interface Vlanif 20 +[Huawei-Vlanif20] ip address 192.168.20.254 255.255.255.0 +``` + +--- + +## 四、静态路由 + +``` +[Huawei] ip route-static 10.0.1.0 255.255.255.0 192.168.1.2 +[Huawei] ip route-static 10.0.1.0 255.255.255.0 GigabitEthernet0/0/0 192.168.1.2 +[Huawei] ip route-static 0.0.0.0 0.0.0.0 192.168.1.1 # 默认路由 +[Huawei] ip route-static 0.0.0.0 0 10.0.0.1 preference 80 # 浮动静态路由(备用) +``` +> 格式:`ip route-static <目标网络> <掩码> <下一跳地址>` 或 `<出接口> <下一跳>` + +--- + +## 五、动态路由协议 + +### 5.1 OSPF(开放最短路径优先) +``` +[Huawei] ospf 1 router-id 1.1.1.1 # 进程号1,指定Router-ID +[Huawei-ospf-1] area 0 # 骨干区域 +[Huawei-ospf-1-area-0.0.0.0] network 192.168.1.0 0.0.0.255 # 宣告网络 +[Huawei-ospf-1-area-0.0.0.0] network 10.0.0.0 0.0.0.0 # 宣告Loopback +[Huawei-ospf-1] stub # 配置为末节区域 +[Huawei-ospf-1] default-route-advertise always # 通告默认路由 +``` + +### 5.2 RIP(路由信息协议) +``` +[Huawei] rip 1 +[Huawei-rip-1] version 2 # RIP v2(支持CIDR和认证) +[Huawei-rip-1] network 192.168.1.0 +[Huawei-rip-1] network 10.0.0.0 +[Huawei-rip-1] undo summary # 关闭自动汇总 +``` + +### 5.3 BGP(边界网关协议) +``` +[Huawei] bgp 65001 # AS号 +[Huawei-bgp] peer 192.168.1.2 as-number 65002 +[Huawei-bgp] network 10.0.0.0 mask 255.255.255.0 +[Huawei-bgp] peer 192.168.1.2 next-hop-local # 强制下一跳为自身 +[Huawei-bgp] peer 192.168.1.2 route-policy LP permit +``` + +--- + +## 六、常用查看命令(最重要的排查手段) + +``` +display ip interface brief # 查看所有接口IP状态速览 ★最常用 +display ip routing-table # 查看路由表 ★最常用 +display vlan # 查看VLAN信息 +display port vlan # 查看端口VLAN分配 +display mac-address # 查看MAC地址表 +display arp # 查看ARP表 +display ospf peer # 查看OSPF邻居状态 +display ospf routing # 查看OSPF路由 +display bgp peer # 查看BGP邻居 +display bgp routing-table # 查看BGP路由表 +display stp # 查看生成树状态 +display stp brief # 查看STP端口角色 +display current-configuration interface GigabitEthernet0/0/1 # 查看指定端口配置 +display logbuffer # 查看日志缓冲区 +display interface GigabitEthernet0/0/0 # 查看接口详细信息(收发包统计等) +display this # 查看当前视图的配置 +``` + +--- + +## 七、网络排障(Troubleshooting) + +``` +ping 192.168.1.2 # 测试连通性 +tracert 10.0.1.1 # 路由追踪 + terminal monitor # 开启日志显示 + terminal debugging # 开启调试输出 +[Huawei] debugging ospf packet hello # 调试OSPF Hello包(用完记得 undo) + display diagnostic-information # 收集所有诊断信息(导出用) +``` + +--- + +## 八、常用功能配置 + +### 8.1 DHCP 服务器 +``` +[Huawei] dhcp enable # 全局启用DHCP +[Huawei] ip pool POOL1 # 创建地址池 +[Huawei-ip-pool-POOL1] network 192.168.1.0 mask 255.255.255.0 +[Huawei-ip-pool-POOL1] gateway-list 192.168.1.254 +[Huawei-ip-pool-POOL1] dns-list 114.114.114.114 8.8.8.8 +[Huawei-ip-pool-POOL1] excluded-ip-address 192.168.1.1 192.168.1.10 +[Huawei] interface Vlanif 10 +[Huawei-Vlanif10] dhcp select global # 接口选择全局地址池 +``` + +### 8.2 NAT(网络地址转换) +``` +# 基础NAT(将内网段NAT到出接口) +[Huawei] acl 2000 +[Huawei-acl-basic-2000] rule 5 permit source 192.168.0.0 0.0.255.255 +[Huawei] interface GigabitEthernet0/0/1 +[Huawei-GigabitEthernet0/0/1] nat outbound 2000 # 在出接口应用ACL做NAT + +# 静态NAT(一对一映射) +[Huawei-GigabitEthernet0/0/0] nat static global 1.2.3.4 inside 192.168.1.10 + +# PAT(端口映射) +[Huawei-GigabitEthernet0/0/0] nat server protocol tcp global 1.2.3.4 80 inside 192.168.1.10 80 +``` + +### 8.3 链路聚合 +``` +[Huawei] interface Eth-Trunk 1 +[Huawei-Eth-Trunk1] trunkport GigabitEthernet 0/0/1 to 0/0/4 +[Huawei-Eth-Trunk1] port link-type trunk +[Huawei-Eth-Trunk1] port trunk allow-pass vlan 10 20 + +# 接口下配置(两种模式) +[Huawei-GigabitEthernet0/0/1] eth-trunk 1 # 静态聚合 +[Huawei-GigabitEthernet0/0/1] lacp priority 100 # LACP模式 +``` + +### 8.4 MSTP(多生成树) +``` +[Huawei] stp region-configuration +[Huawei-mst-region] region-name MENGYA +[Huawei-mst-region] instance 1 vlan 10 20 +[Huawei-mst-region] instance 2 vlan 30 40 +[Huawei-mst-region] active region-configuration +[Huawei] stp instance 1 root primary # 指定该交换机为实例1的根桥 +[Huawei] stp instance 2 root secondary +``` + +### 8.5 VRRP(虚拟路由冗余协议) +``` +[Huawei] interface Vlanif 10 +[Huawei-Vlanif10] vrrp vrid 1 virtual-ip 192.168.10.1 +[Huawei-Vlanif10] vrrp vrid 1 priority 120 # 优先级越高越可能为主 +[Huawei-Vlanif10] vrrp vrid 1 preempt-mode timer delay 10 # 抢占延迟 +[Huawei-Vlanif10] vrrp vrid 1 track interface GigabitEthernet0/0/0 reduced 30 # 上行接口追踪 +``` + +### 8.6 ACL(访问控制列表) +``` +# 基本ACL(基于源IP) +[Huawei] acl 2000 +[Huawei-acl-basic-2000] rule 5 deny source 192.168.1.0 0.0.0.255 +[Huawei-acl-basic-2000] rule 10 permit source any + +# 高级ACL(基于源/目的IP+端口) +[Huawei] acl 3000 +[Huawei-acl-adv-3000] rule 5 deny tcp source 10.0.0.0 0.0.0.255 destination 172.16.0.0 0.0.0.255 destination-port eq 22 +[Huawei-acl-adv-3000] rule 10 permit ip + +# 应用到接口 +[Huawei-GigabitEthernet0/0/1] traffic-filter inbound acl 3000 +``` + +--- + +## 九、eNSP 特有设置(模拟器层面) + +``` +[Huawei] undo terminal monitor # 关闭终端监控弹出 +[Huawei] user-interface console 0 # 进入console配置 +[Huawei-ui-console0] idle-timeout 0 # 取消超时自动断开(方便实验) +[Huawei] info-center source default logbuffer level warning # 减少日志输出干扰 +``` + +--- + +## 十、速查口诀 + +| 场景 | 命令口诀 | +|------|---------| +| 进配置 | `system-view` | +| 配IP | `interface xxx` → `ip address x.x.x.x x.x.x.x` | +| 配VLAN | `vlan batch` → 端口 `port link-type access/trunk` → `port default vlan` | +| 三层交换 | `interface Vlanif x` → 配IP | +| 静态路由 | `ip route-static 目标网段 掩码 下一跳` | +| OSPF | `ospf x` → `area 0` → `network x.x.x.x x.x.x.x.x` | +| 保存 | `save` → `Y` | +| 查看配置 | `display current-configuration` | +| 查看端口 | `display ip interface brief` | +| 查看路由 | `display ip routing-table` | +| 清配置 | `reset saved-configuration` → `reboot` | diff --git a/mengyanote-backend/data/mengyanote/运维/nginx快速配置反向代理.md b/mengyanote-backend/data/mengyanote/运维/nginx/nginx快速配置反向代理.md similarity index 100% rename from mengyanote-backend/data/mengyanote/运维/nginx快速配置反向代理.md rename to mengyanote-backend/data/mengyanote/运维/nginx/nginx快速配置反向代理.md diff --git a/mengyanote-backend/data/mengyanote/运维/nginx模块大全.md b/mengyanote-backend/data/mengyanote/运维/nginx/nginx模块大全.md similarity index 98% rename from mengyanote-backend/data/mengyanote/运维/nginx模块大全.md rename to mengyanote-backend/data/mengyanote/运维/nginx/nginx模块大全.md index 7b3cfe7..71c0374 100644 --- a/mengyanote-backend/data/mengyanote/运维/nginx模块大全.md +++ b/mengyanote-backend/data/mengyanote/运维/nginx/nginx模块大全.md @@ -1,9 +1,5 @@ ## 官方模块(NGINX 官方文档 Modules reference 列表) -好家伙,这是一份**Nginx 官方模块全家桶** 😄 -我给你在**后面新增一列「一句话说明」**,每个模块都用**一句话、偏功能点**来解释,方便你查阅 / 做文档 / 选型。 - --- - ### HTTP 模块 | 分类 | 模块名 | 子系统 | 说明 | diff --git a/mengyanote-backend/data/mengyanote/运维/减少运营商对udp的qos限制.md b/mengyanote-backend/data/mengyanote/运维/减少运营商对udp的qos限制.md index fd2404a..aff9e2e 100644 --- a/mengyanote-backend/data/mengyanote/运维/减少运营商对udp的qos限制.md +++ b/mengyanote-backend/data/mengyanote/运维/减少运营商对udp的qos限制.md @@ -107,7 +107,3 @@ MTU = 1420 |避免长连接被识别|动态端口+周期断连| |降低丢包 & 分片|调整 MTU| |增强抗 QoS 能力|多路径 / 多端口方案| - ---- - -如果你愿意,我还可以给出 **具体的 wg-quick + udp2raw 配置示例** 或 **服务端脚本自动化方案**。需要的话告诉我你的服务器环境(Linux/WSL/OpenWrt 等)。 \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/运维/域名的三种设置(自上而下).md b/mengyanote-backend/data/mengyanote/运维/域名跳转的三种设置(自上而下).md similarity index 100% rename from mengyanote-backend/data/mengyanote/运维/域名的三种设置(自上而下).md rename to mengyanote-backend/data/mengyanote/运维/域名跳转的三种设置(自上而下).md diff --git a/mengyanote-backend/data/mengyanote/运维/快速申请https证书并配置自动续期.md b/mengyanote-backend/data/mengyanote/运维/快速申请https证书并配置自动续期.md index a32888e..404a0a5 100644 --- a/mengyanote-backend/data/mengyanote/运维/快速申请https证书并配置自动续期.md +++ b/mengyanote-backend/data/mengyanote/运维/快速申请https证书并配置自动续期.md @@ -1,6 +1,3 @@ -下面是快速在公网服务器上申请一个免费的、并能自动续期的 HTTPS 证书的实用方案 - ---- ## ✅ 推荐方式(最简单最快速) diff --git a/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/SQL题:查某个班级下所有学生的选课情况.md b/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/SQL题:查某个班级下所有学生的选课情况.md new file mode 100644 index 0000000..df58903 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/SQL题:查某个班级下所有学生的选课情况.md @@ -0,0 +1,42 @@ +有三张表:学生信息表、学生选课表、学生班级表 +学生信息表(students)结构如下: + +```sql +CREATE TABLE students ( + student_id INT PRIMARY KEY, -- 学生的唯一标识,主键 + student_name VARCHAR(50), -- 学生姓名 + class_id INT -- 学生所属班级的标识,用于关联班级表 +); +``` +学生选课表(course_selections)结构如下: + +```sql +CREATE TABLE course_selections ( + selection_id INT PRIMARY KEY, -- 选课记录的唯一标识,主键 + student_id INT, -- 选课学生的标识,用于关联学生信息表 + course_name VARCHAR(50) -- 所选课程的名称 +); +``` +学生班级表(classes)结构如下: + +```sql +CREATE TABLE classes ( + class_id INT PRIMARY KEY, -- 班级的唯一标识,主键 + class_name VARCHAR(50) -- 班级名称 +); +``` + +```sql +SELECT + s.student_id, + s.student_name, + cs.course_name +FROM + students s +JOIN + course_selections cs ON s.student_id = cs.student_id +JOIN + classes c ON s.class_id = c.class_id +WHERE + c.class_name = 'Class A'; +``` \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/sql题:给学生表、课程成绩表,求不存在01课程但存在02课程的学生的成绩.md b/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/sql题:给学生表、课程成绩表,求不存在01课程但存在02课程的学生的成绩.md new file mode 100644 index 0000000..a84d330 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/sql题:给学生表、课程成绩表,求不存在01课程但存在02课程的学生的成绩.md @@ -0,0 +1,18 @@ +```sql +SELECT s.sid,s.sname,sc2.cid,sc2.score +FROM Student s +LEFT JOIN Score AS sc1 ON s.sid = AND sc1.cid = '01' +LEFT JOIN Score AS sc2 ON s.sid = AND sc2.cid = '02' +WHERE sc1.cid IS NULL AND sc2.cid IS NOT NULL; + + +``` + +```sql +SELECT s.sid, s.sname, sc.cid, sc.score +FROM Student s +JOIN Score sc ON s.sid = sc.sid AND sc.cid = '02' +WHERE NOT EXISTS ( + SELECT 1 FROM Score sc1 WHERE sc1.sid = s.sid AND sc1.cid = '01' +); +``` \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/如何用 MySQL 实现一个可重入的锁?.md b/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/如何用 MySQL 实现一个可重入的锁?.md new file mode 100644 index 0000000..119e8f6 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/如何用 MySQL 实现一个可重入的锁?.md @@ -0,0 +1,12 @@ +```sql +CREATE TABLE `lock_table` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + //该字段用于存储锁的名称,作为锁的唯一标识符。 + `lock_name` VARCHAR(255) NOT NULL, + // holder_thread该字段存储当前持有锁的线程的名称,用于标识哪个线程持有该锁。 + `holder_thread` VARCHAR(255), + // reentry_count 该字段存储锁的重入次数,用于实现锁的可重入性 + `reentry_count` INT DEFAULT 0 +); + +``` \ No newline at end of file diff --git a/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/给定一个学生表 student_score(stu_id,subject_id,score),查询总分排名在5-10名的学生id及对应的总分.md b/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/给定一个学生表 student_score(stu_id,subject_id,score),查询总分排名在5-10名的学生id及对应的总分.md new file mode 100644 index 0000000..505a241 --- /dev/null +++ b/mengyanote-backend/data/mengyanote/面试求职/SQL面试题/给定一个学生表 student_score(stu_id,subject_id,score),查询总分排名在5-10名的学生id及对应的总分.md @@ -0,0 +1,26 @@ +```sql +WITH StudentTotalScores AS ( + SELECT + stu_id, + SUM(score) AS total_score + FROM + student_score + GROUP BY + stu_id +), +RankedStudents AS ( + SELECT + stu_id, + total_score, + RANK() OVER (ORDER BY total_score DESC) AS ranking + FROM + StudentTotalScores +) +SELECT + stu_id, + total_score +FROM + RankedStudents +WHERE + ranking BETWEEN 5 AND 10; +``` \ No newline at end of file