资讯详情

算法刷题第47天:一小时复习Dijkstra、背包DP与二分边界

📅 2026/10/13 21:53:54 | 华诺云谱 👁 阅读
算法刷题第47天:一小时复习Dijkstra、背包DP与二分边界
0x3f 第47天 复习 9:24-10:24——这个字符串是我每天都在刷题打卡的标题格式代号 第几天 今天干什么 时间区间。今天是整轮计划的第47天安排的内容是复习从早上9:24到10:24刚好六十分钟。标题看起来平平无奇但对一个连续刷题四十多天的人来说主动把黄金一小时从刷新题里抠出来做复习其实是个挺反直觉的决定。如果你也在坚持算法打卡或者正处于题刷了不少、但一合上笔记就写不出来的状态这篇记录应该能帮到你。我会把今天这一小时从头到尾拆开讲为什么第47天非复习不可、一小时怎么分配到分钟级、复习时具体查了哪些知识点、又踩了哪些只有重写代码才会暴露的坑。里面还会附上我整理的易错清单和时间模板都是真实试过且有效的做法。1. 先解释0x3f这个代号里面藏着一个算法常识1.1 代号其实是十六进制的630x3f是我给自己定的学习代号来历非常朴素。有一次组队练习抽签我抽到63号十六进制写出来就是0x3f后来直接拿来当网名和打卡前缀。用久了反而觉得这名字挺妙每次看到它我第一反应不是数字63而是算法竞赛里那个经典无穷大常量0x3f3f3f3f。在很多最短路模板里dist数组初始化写作memset(dist, 0x3f, sizeof(dist))。为什么不用INT_MAX或者十进制1061109567原因很实际memset按字节填充0x3f的每个字节都是0x3f四个字节拼起来正好是0x3f3f3f3f约等于10^9。这个数比真实最短路长得多又比int上限2147483647小所以初始化和更新时不容易溢出。我就是从这个代号出发把一堆图论初始化细节又顺了一遍。1.2 第47天处在计划的什么阶段我给自己定的计划是一百天左右的算法专项提升第47天正好卡在中间偏后的位置。这个节点的典型状态是新知识点堆了不少最短路、背包DP、并查集、二分答案都过过一遍但过了一遍和真正会了之间隔着一条巨大的鸿沟。前几天我试着不翻笔记手写带堆优化的Dijkstra写到一半卡住了转移思路倒是记得但堆里pair的存取顺序搞反了。那一刻我意识到不能再闷头推新题了必须腾出整块时间做一次系统复习。所以这篇打卡记录尤其适合两类人一类是像我一样在长期刷题、但开始觉得知识往外漏的人另一类是刷题数量上去了、却总在基础题上莫名翻车的人。复习不是退步恰恰是把前面所有表面学会变成真正掌握的补票机会。2. 为什么要专门安排一小时复习刷题数量会骗人2.1 过题记录带来的错觉连续刷题很容易产生一种错觉只要今天又过了几道题就代表我在稳步进步。但过题记录反映的是那一刻做对了一道题完全不代表一周后还能独立写出来。我观察过自己很久任何一个算法学完当天感觉通透第三天就只剩大概印象到了第七天基本只能说出我好像学过。这不是记忆力差而是缺少提取练习。打个比方背单词只背不复习背到第200个时前面50个基本剩不下多少。刷题也一样而且算法知识比单词更复杂遗忘之后靠重读笔记很难捡起来最有效的恢复方式是直接动手重写。2.2 复习的定义不是看一遍而是写出来我对复习的要求很严格关掉模板关掉旧代码只看题目描述或知识点名字独立把代码写出来。写不出或写错了才算真正发现薄弱点。整个过程本质是自我测验目的不是自我感动而是让刚刚好像懂了变成不用想就能写的肌肉记忆。今天六十分钟我给自己定的目标很简单不贪多集中查三个主题——堆优化Dijkstra、一道之前反复出错的背包DP、二分答案的整数边界。这三个都是最近两周碰过的也是我判断自己最容易遗忘的点。复习内容不能随便抓得讲究优先级取舍逻辑后面细说。3. 一小时复习怎么拆我实际的时间切片3.1 前5分钟把复习清单写出来开始复习前我先花几分钟翻最近两周的做题记录把所有值得复习的点列出来再按优先级挑出今天要处理的三个。我的取舍规则是优先复习下周马上要用的和最近新学的其次是错得最惨的最后才是纯想巩固的。一小时很有限贪心想全覆盖的结果通常是一个都没复习透。列清单这个动作看起来简单其实决定了复习成败。没有清单的复习很容易变成翻开笔记随便看看看着看着就去研究新东西最后什么都没沉淀。今天的清单我写在白纸左侧Dijkstra堆优化、背包DP初始化、二分边界。写完定了个闹钟开始默写。3.2 20分钟默写核心模板而不是读模板第一个复习堆优化Dijkstra。关掉所有代码从建图开始在白纸上写。第一次写出来就卡在初始化memset第二个参数到底传0x3f还是0x3f3f3f3f答案是0x3f因为这个函数只认单个字节。继续往下写堆里存什么我习惯存pairlong long, int第一位距离第二位节点编号。priority_queue默认是大根堆所以必须声明成小根堆或者存距离时取负。这一步我犹豫了半分钟。完整写出来后对照正确模板检查发现一个隐蔽问题邻接表存稀疏图时如果两个节点之间有重边插入时不能直接覆盖必须保留最短的那条。很多入门模板不会特意讲这个但题故意给重边时代码就会挂。我把这个点记在了清单旁边整个过程大概20分钟重点不是写多快而是每写一步都清楚为什么会这么写。3.3 25分钟不看旧代码重做一道错题接着我选了一道最近反复出错的背包DP题当时第一次提交把转移方程写反了后来看了别人思路才勉强通过。今天的复习要求是彻底重新写一遍不允许看旧代码。结果一上手问题就暴露了我居然在初始化上犹豫了很久。01背包倒序遍历容量、完全背包正序遍历容量这个我倒是记得但我忘了恰好装满和不超过容量两种问法在初始化上的差别。恰好装满要求dp[0] 0其他状态初始化为负无穷不超过容量则全部初始化为0。这次复习让我出了一身冷汗如果明天竞赛遇到这类题我大概率会栽在初始化上。后来我在白纸上重新推导一遍转移方程把dp[j]用文字描述出来前i个物品中选若干个使容量恰好为j时的最大价值。定义一清晰转移方程就顺理成章了。这25分钟让我确认复习错题的价值远大于再做三道没见过的简单题。3.4 10分钟把暴露的问题整理进遗忘清单最后十分钟我没有再开新题而是把所有卡壳点整理进一个固定格式的复习文档知识点、暴露的问题、是否已解决、下次复查日期。今天的记录大概是Dijkstra堆优化pair排序方式犹豫已解决3天后复查背包DP恰好装满初始化不熟已解决3天后复查二分边界还没开始验证明天上午重点看。整理完一小时刚好结束9:24开始的复习在10:24准时收尾。4. 复习现场高频考点到底容易错在哪既然今天复习的主要是基础算法我顺便把这次复盘时重新梳理的高频易错点写出来。这些不算竞赛大佬才懂的神仙优化而是普通刷题人最容易在模板题上翻车的细节。4.1 最短路与INF的溢出陷阱堆优化Dijkstra核心代码不长但dist初始化的写法很讲究。很多人用memset(dist, 0x3f, sizeof(dist))没问题但要注意后续更新判断。如果写成if(dist[v] dist[u] w)而dist[u]和w都接近0x3f3f3f3f相加后可能超过int上限得到一个负数然后整条最短路就崩了。我复习时给自己定了个习惯所有涉及距离和边权的地方都开long long判断不可达时直接比较if(dist[v] INF)而不是先相加再比较。即使数组是long longmemset依然可用因为按字节填充的原理一致。这条记进笔记以后写最短路直接沿用。4.2 背包DP初始化取决于题目问法背包DP里最坑的就是初始化。同样是01背包问容量不超过V时最大价值dp数组全部初始化为0就行问恰好装满V时最大价值则dp[0]0其他初始化为负无穷因为那些状态初始不可达。很多题解只贴代码不解释导致大家背板子背熟了一换问法就错。我复习时会把为什么这么初始化写一遍再拿最小数据手动演算一遍。比如V5物品只有一个体积3价值4。恰好装满时答案是不可行不超过容量时答案是4。两者结果完全不同代码却只差一行初始化。4.3 并查集和线段树的隐藏坑并查集的路径压缩大家都会写但数据范围一大递归路径压缩可能因为递归层数过深导致栈溢出。我建议直接用迭代版本代码几乎一样却更稳。另外如果只压缩路径、不按秩合并极端数据下树还是会很深查询退化成接近O(N)。所以merge时建议根据size或rank合并小树到大树。线段树最值得复习的是懒标记。区间加、区间赋值、区间乘混在一起时下传顺序非常容易乱。我一般会给每个节点存待下传的累加值和覆盖值下传时先处理覆盖再处理累加因为如果先加后覆盖覆盖会把加法结果清掉。这个顺序问题当初困扰了我一整天后来整理成固定模板才消停。4.4 整数二分边界为什么容易死循环二分答案边界问题刷了几十题的人也一样会翻车。整数二分最容易出现死循环比如求满足条件的最大值时写成mid (l r) / 2再执行l mid当区间长度为2时就永远收缩不了。正确写法是向上取整mid (l r 1) / 2这样才能保证l mid时区间真正缩小。我的复习口诀是找最小值用右边界收缩mid(lr)/2lmid1找最大值用左边界扩张mid(lr1)/2rmid-1。写的时候对着口诀核对基本不出错。4.5 数组越界的隐蔽性最后一个吐槽所有算法题通用的坑数组越界。越界不一定崩溃常常只是读到相邻数组的垃圾值导致极端数据下突然出错。我复习时养成了习惯凡是开数组的算法开完立刻检查下标范围n最大多少数组长度是不是留了足够冗余比如n5或n*4。这个习惯看着土真能省下大量排查时间。5. 复习过程中最常踩的五个坑与排查方法今天一个小时里我自己也有几次烦躁到想放弃的时刻。这里把常见的几个坑整理成速查表下次遇到症状可以直接对照。症状可能原因排查与处理代码跑了但结果偏大或偏小初始化错误、循环边界取值不对先检查初始化和边界再用最小样例手算一遍样例能过但提交超时复杂度分析失误或死循环检查二分区间是否收缩检查循环是否写成最坏情况偶尔报错本地测不出来数组越界或变量未初始化打开编译器警告数组开大一个量级用最大n测试重写比第一次写还慢算法只有模糊印象没有形成稳定模板先回到原理层面画状态图再闭卷重写复习完感觉什么都没记住复习太散没有明确输出强制自己默写代码并写下易错点有输出才算复习完成每次复习完我至少挑两三个情况复盘。尤其是重写比第一次还慢这个症状在长时间不碰某个算法后特别常见。我的体会是这时候不能急着继续写先回到算法核心思想想清楚状态怎么转移、边界怎么收缩再闭卷写。写得慢不一定是不努力但一定说明原理理解不够深。6. 把一小时复习变成长期机制而不只是一次打卡6.1 打卡日志要记四件事今天这次复习让我改掉了打卡日志的格式。以前我只记今天做了几题现在固定记录四部分今日新题、今日复习、暴露问题、明日计划。新题和复习体现广度和深度暴露问题才是复盘最重要的产出明日计划保证问题不会被拖着拖着就没了。举个今天的例子日志标题是0x3f 第47天 复习 9:24-10:24内容我写的是新题0道复习Dijkstra堆优化、背包DP初始化、二分边界暴露问题包括恰好装满初始化不熟、pair排序方式犹豫明日计划是做一道完全背包重点验证二分最大值模板。过一个月回来看我依然能知道自己当时卡在哪。6.2 日复习、周复习、月复习怎么排我给自己定的复习节奏分三层。日常复习约5分钟主要是在打卡日志上标注昨天学的知识点有没有忘每周专门安排一小时像今天这样深挖三四个主题每月拿出半天把所有遗忘清单过一遍至少选两道错题独立重写。这种节奏的目的不是增加负担而是让复习嵌入学习而不是临时抱佛脚。6.3 第47天的心态调整47天正好是容易疲惫的阶段。新内容学了不少离大成还远中途没有太多里程碑式反馈。我发现复习其实是很好的正反馈来源当你默写出一个大体正确的模板时你会真切地感到自己真会了这种踏实感比闷头刷新题强很多。如果你也正进行到计划一半左右感到疲劳不妨把节奏从开新题切换成复习旧题。今天最大的收获反而不是某个具体细节而是重新确认了一件事持续学习的动力很大程度来自对已有知识的掌控感。第47天能在9:24到10:24之间完成一次有效复习让我觉得前面四十多天刷过的题都没有白费。明天进入第48天我继续保持这个节奏也建议你给自己安排一个固定复习时段哪怕一周只有一小时效果也会比你想象中明显。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑