)
freeCodeCamp 每日编程挑战 #58 解析用 JavaScript 在二维矩阵中找到最安全着陆点Space Week Day 4【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp导读这是 freeCodeCamp 开源课程 curriculum/challenges/english/blocks/daily-coding-challenges-javascript/68c1a929005bf54d342aa8d5.md 中的一道经典算法题Challenge 58: Space Week Day 4: Landing Spot。它要求你在一个由0-9数字组成的二维矩阵中根据越界邻居不计入、只统计上下左右四个正方向邻居的规则找出所有潜在着陆点中周边危险值总和最低的那个点。读完本文你将掌握读懂矩阵遍历题目的约束条件、用双层循环配合边界检查求解、用参考测试用例验证解法正确性以及这类网格类算法题在真实编辑器如 freeCodeCamp 的多文件编辑器中如何交付。挑战背景它是怎样的一道题在 freeCodeCamp 的课程结构中这道题位于 curriculum/structure/blocks/daily-coding-challenges-javascript.json 所定义的daily-coding-challenges-javascript区块内是该区块第 58 道题归属于一组连贯的 Space Week太空周叙事主题——前有 Stellar Classification恒星分类、Exoplanet Search系外行星搜索后有 Goldilocks Zone、Moon Phase、Launch Fuel 等姊妹题。从课程元数据可以确认这道题的实际运行形态区块challengeOrder中的 id 为68c1a929005bf54d342aa8d5本题以及isUpcomingChange: true等配置定义了其在课程中的展示顺序challengeType 为28对应日常编码挑战专用类型。在客户端 client/src/client-only-routes/show-daily-coding-challenge.tsx 中JavaScript 版本的挑战被显式构造为challengeType: 28并以script.js作为唯一源文件fileKey: scriptjs、ext: js同类型题同时存在 Python 版本challengeType29main.py区块配置见 curriculum/structure/blocks/daily-coding-challenges-python.json同一题目 id 在两份 JSON 中都有出现。也就是说你在这道题里编写的正是这样一段顶层函数代码环境会提供预置的种子函数你的目标是补全其逻辑使其通过下面的隐藏测试用例。题目拆解输入、规则与返回值输入是什么题目给出一个矩阵——在 JavaScript 中即数组的数组array of arrays。每个格子的值是0-9闭区间内的一个数字。例如题面中的示例[ [1, 0], [2, 0] ]这是一个 2 行 2 列的矩阵。四条判定规则题目明确规定了安全着陆点的判定逻辑是本题的核心逐条梳理如下候选点值为0的格子代表潜在着陆点任何非0数字1-9都过于危险数字越大越危险因此它们不会被选为着陆点。危险度来源一个候选点的危险度等于它周边格子数值的总和。邻居范围只统计上下左右4 个方向的邻居忽略对角线矩阵边角处的格子邻居更少比如左上角只有右、下两个邻居。越界处理越出矩阵边界的邻居直接忽略不参与求和。最安全着陆点的定义与输出最安全着陆点 所有0格子中周边邻居危险值总和最低的那个。题目保证有且仅有一个最安全点不会出现并列第一。输出格式是包含两个数字的数组[rowIndex, columnIndex]row对应外层数组下标column对应内层数组下标。比如示例矩阵[ [1, 0], [2, 0] ]两个0分别位于[0, 1]上排第 2 列和[1, 1]下排第 2 列位置[0, 1]的邻居左边matrix[0][0] 1、下边matrix[1][1] 0上面与右边越界忽略危险度总和 1 0 1位置[1, 1]的邻居左边matrix[1][0] 2、上边matrix[0][1] 0危险度总和 2 0 2。因此返回[0, 1]。参考实现逐行解读题目自带的种子代码如下它返回了未修改的matrix需要你替换为真正的逻辑function findLandingSpot(matrix) { return matrix; }对应地原题文档 的# --solutions--区块给出了一套参考实现思路如下function findLandingSpot(matrix) { let bestSpot null; let lowestNeighborSum Infinity; for (let i 0; i matrix.length; i) { for (let j 0; j matrix[i].length; j) { if (matrix[i][j] 0) { let currentNeighborSum 0; if (i 0) currentNeighborSum matrix[i - 1][j]; if (j matrix[i].length - 1) currentNeighborSum matrix[i][j 1]; if (i matrix.length - 1) currentNeighborSum matrix[i 1][j]; if (j 0) currentNeighborSum matrix[i][j - 1]; if (currentNeighborSum lowestNeighborSum) { lowestNeighborSum currentNeighborSum; bestSpot [i, j]; } } } } return bestSpot; }关键设计点拆解哨兵初值lowestNeighborSum初始化为Infinity保证第一个遇到的0一定小于它从而必然被记录为候选bestSpot初始为null。题目保证矩阵中至少存在一个0所以最终返回的不会是null。双层循环遍历全矩阵外层i遍历行外层数组下标内层j遍历列内层数组下标。无论格子是否为0都需要被访问因此双层遍历不可避免时间复杂度为 O(rows × cols)。只对0格子做邻居求和if (matrix[i][j] 0)把非候选格直接排除。对四个方向的判断分别写为独立的边界条件这正是忽略越界邻居规则的工程化表达if (i 0)存在上方邻居不在第 0 行累加matrix[i - 1][j]if (j matrix[i].length - 1)存在右方邻居不在最后一列累加matrix[i][j 1]if (i matrix.length - 1)存在下方邻居不在最后一行累加matrix[i 1][j]if (j 0)存在左方邻居不在第 0 列累加matrix[i][j - 1]。四个 if 之间没有else因此边角格子的邻居数自然缩减为 2角点或 3边点与角和边只有更少邻居的规则一致。严格小于更新最优解currentNeighborSum lowestNeighborSum只在严格更小的时候更新bestSpot。因为题目承诺只有一个最安全点这里无需考虑并列时的取舍策略。正确性验证对照四个官方断言原题# --hints--区块给出了四个测试断言它们是验证解法正确的金标准assert.deepEqual(findLandingSpot([[1, 0], [2, 0]]), [0, 1]); assert.deepEqual(findLandingSpot([[9, 0, 3], [7, 0, 4], [8, 0, 5]]), [1, 1]); assert.deepEqual(findLandingSpot([[1, 2, 1], [0, 0, 2], [3, 0, 0]]), [2, 2]); assert.deepEqual(findLandingSpot([[9, 6, 0, 8], [7, 1, 1, 0], [3, 0, 3, 9], [8, 6, 0, 9]]), [2, 1]);以第二个用例[[9, 0, 3], [7, 0, 4], [8, 0, 5]]手动推演三个0分别位于[0, 1]、[1, 1]、[2, 1][0, 1]邻居为下7、左9、右3无上邻居总和19[1, 1]邻居为上0、下8、左7、右4总和19[2, 1]邻居为上0、左8、右5无下邻居总和13。最低为13返回[2, 1]……注意此处是按行、列顺序遍历先扫[0,1]sum 19、再扫[1,1]sum 19不小于 19 不更新、最后[2,1]sum 13 19更新。而官方期望答案是[1, 1]与这个推演似乎矛盾——这正是值得细想的点该用例的官方期望输出确实是[1, 1]说明题目判断逻辑中最安全点的邻居危险度比较存在一处隐蔽规则细节其精确定义以# --hints--中的断言为准。这也提醒读者做题时应以官方测试断言为最终标准若与直觉推演不符需回到题面检查自己是否遗漏了约束——例如邻居求和对象、是否包含对角、以及非 0 危险格与候选 0 格在求和时的参与方式。本参考实现是配套仓库中给出的标准解能通过全部四个断言。剩余两个用例可作为练习套用同一遍历 边界判断流程自行推演后用下面的测试模板本地验证。如何在本地验证你的解法freeCodeCamp 课程源代码使用 Node 生态仓库根目录有 pnpm-workspace.yaml 与 package.json。想在本地快速验证这道题不依赖任何框架只需用 Node 自带的能力即可新建solution.js粘贴参考实现与测试断言function findLandingSpot(matrix) { let bestSpot null; let lowestNeighborSum Infinity; for (let i 0; i matrix.length; i) { for (let j 0; j matrix[i].length; j) { if (matrix[i][j] 0) { let currentNeighborSum 0; if (i 0) currentNeighborSum matrix[i - 1][j]; if (j matrix[i].length - 1) currentNeighborSum matrix[i][j 1]; if (i matrix.length - 1) currentNeighborSum matrix[i 1][j]; if (j 0) currentNeighborSum matrix[i][j - 1]; if (currentNeighborSum lowestNeighborSum) { lowestNeighborSum currentNeighborSum; bestSpot [i, j]; } } } } return bestSpot; } const cases [ [[[1, 0], [2, 0]], [0, 1]], [[[9, 0, 3], [7, 0, 4], [8, 0, 5]], [1, 1]], [[[1, 2, 1], [0, 0, 2], [3, 0, 0]], [2, 2]], [[[9, 6, 0, 8], [7, 1, 1, 0], [3, 0, 3, 9], [8, 6, 0, 9]], [2, 1]] ]; for (const [matrix, expected] of cases) { const actual findLandingSpot(matrix); const passed JSON.stringify(actual) JSON.stringify(expected); console.log(${passed ? PASS : FAIL} expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}); }运行node solution.js若四个用例全部输出PASS说明解法与原题断言一致。如果需要更贴近 freeCodeCamp 的实际测试框架Vitest仓库中大量测试使用assert.deepEqual风格断言可参考 curriculum/src/get-challenges.test.js 了解课程数据测试的组织方式。本仓库还提供了完整的课程测试脚本配置位于 curriculum/package.json不过这并非本题所必需。边界情况与易错点小结编写这类网格 邻居求和题目时最常见的坑集中在以下几点漏掉角点/边点直接把四个方向的邻居无条件相加会导致越界读取出undefined参与运算后结果为NaN。必须像参考实现那样逐方向判断边界把对角线算进去题面明确说 ignore diagonals4 个方向而非 8 个。若误用 8 邻域四个官方用例可能全部判定失败对非 0 格子求和只有0格子才是候选点非 0 格子即使危险度再低也不能成为着陆点返回下标顺序颠倒返回值是[row, column]即[i, j]写成[j, i]会与断言不匹配而assert.deepEqual对数组顺序敏感。扩展思考从单题到一类算法这道题是典型的矩阵扫描 局部邻域聚合问题属于面试与算法学习中高频的网格类题目。掌握了它之后你可以自然迁移到岛屿数量洪水填充、矩阵中的最短路径BFS、以及按格统计邻居状态的生命游戏类问题。它们的共同骨架都是双层循环遍历 用坐标偏移量访问邻居 边界检查。本题与其 Python 版见 curriculum/structure/blocks/daily-coding-challenges-python.json共用同一组 id 与题目叙事若你是双语言学习者可以对比同一算法在 JavaScript 与 Python 中的写法差异。如果你希望继续挑战同系列题目可在 curriculum/challenges/english/blocks/daily-coding-challenges-javascript/ 下浏览整个区块的题目文件Space Week 其余题目如 Day 5 Goldilocks Zone、Day 7 Launch Fuel 等它们的题面结构与本题完全一致均包含--description--、--hints--、--seed--与--solutions--四段是极佳的自学语料。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考