codevs1163 访问艺术馆 树型数组 记忆化搜索

578 篇文章 ¥299.90 ¥399.90
570 篇文章 ¥299.90 ¥399.90
该博客介绍了如何帮助盗画者皮尔在警察赶到前利用树型数组和记忆化搜索算法,计算最多能偷走的艺术馆画作数量。题目描述了艺术馆的结构和时间限制,警察赶到的时间不超过600秒,走廊数量不超过100,每个展室最多20幅画。博客内容包括问题定义、输入输出格式和样例解析,旨在引导读者理解并解决这个问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述 Description

    皮尔是一个出了名的盗画者,他经过数月的精心准备,打算到艺术馆盗画。艺术馆的结构,每条走廊要么分叉为二条走廊,要么通向一个展览室。皮尔知道每个展室里藏画的数量,并且他精确地测量了通过每条走廊的时间,由于经验老道,他拿下一副画需要5秒的时间。你的任务是设计一个程序,计算在警察赶来之前(警察到达时皮尔回到了入口也算),他最多能偷到多少幅画。

<think>好的,我现在需要解决用户的问题:如何将JavaScript中的形结构数组进行扁平化处理。首先,我得回顾一下用户提供的引用内容,看看有没有可以参考的代码或方法。用户引用了三个示例,其中引用1和引用3都是关于形结构扁平化的方法。引用1使用递归的方式遍历,将每个节点及其子节点压入结果数组,同时处理父节点ID。引用3则是用reduce方法递归展开子节点。这两个方法都是可行的,但具体实现上有些不同。 接下来,我需要考虑用户的需求是什么。用户可能有一个形结构的数据,比如带有children属性的对象数组,想要将其转换为一个扁平数组,每个节点包含自身信息及父节点的ID。这在处理数据时很常见,比如在展示目录结构或者处理嵌套数据时。 然后,我需要确定如何将这些方法整合成适合用户的最佳方案。用户可能希望方法简单易懂,同时兼顾效率和可扩展性。递归是常用的方法,但需要注意栈溢出的问题,不过对于一般的结构深度,递归应该没问题。另外,用户可能需要保留父节点的信息,方便后续处理,比如构建路径或查找上级节点。接下来,我需要分步骤思考如何实现这个扁平化方法。首先,函数需要接收数组、父节点ID(初始时为undefined或null)和结果数组。遍历每个节点,将当前节点信息(包括id、parentId和其他属性)推入结果数组。如果该节点有子节点,递归调用函数处理子节点,传入当前节点的ID作为父节点ID。还要注意是否需要深拷贝节点,避免修改原数据。根据引用1的示例,直接修改原节点添加parentId可能会影响原数据,所以可能需要创建一个新对象。例如,使用展开运算符复制原有属性,并添加parentId。另外,引用3中的方法使用reduce来展开节点,但可能没有处理父节点ID。用户可能需要明确每个节点的父节点,所以引用1的方法更合适。 测试用例也是重要的,需要验证函数是否正确处理不同层级的节点,并正确设置parentId。例如,根节点的parentId应为undefined或null,子节点的parentId指向父节点的id。最后,总结不同方法的优缺点。递归方法简单直观,但可能不适合极深层次的。迭代方法(如使用栈或队列)可以避免递归的栈溢出问题,但代码复杂度稍高。根据用户的需求,提供两种方法可能更好,让用户根据具体情况选择。现在,我需要将这些思考整理成步骤清晰的回答,并生成相关问题,帮助用户进一步理解或解决潜在的问题。</think>### JavaScript形结构数组扁平化方法 #### 方法一:递归遍历法(保留父节点ID) ```javascript function flattenTree(tree, parentId = undefined, result = []) { for (const node of tree) { // 创建新对象避免污染原始数据 const newNode = { ...node, // 展开原有属性 parentId // 添加父节点ID }; delete newNode.children; // 移除子节点属性 result.push(newNode); if (node.children && node.children.length > 0) { flattenTree(node.children, node.id, result); // 递归处理子节点 } } return result; } // 测试数据 const treeData = [{ id: 1, value: 'A', children: [{ id: 2, value: 'B', children: [{id: 3, value: 'C'}] }] }]; console.log(flattenTree(treeData)); /* 输出: [ {id:1, value:'A', parentId:undefined}, {id:2, value:'B', parentId:1}, {id:3, value:'C', parentId:2} ] */ ``` #### 方法二:迭代法(使用栈) ```javascript function flattenTreeIterative(tree) { const stack = [...tree]; const result = []; const parentMap = new Map(); // 记录父节点ID while (stack.length > 0) { const node = stack.pop(); const parentId = parentMap.get(node); result.push({ ...node, parentId }); if (node.children) { // 将子节点入栈并记录父节点ID node.children.forEach(child => { parentMap.set(child, node.id); stack.push(child); }); } } return result; } ``` #### 方法对比 | 特性 | 递归法 | 迭代法 | |-----------|------------------------------|------------------------------| | 时间复杂度 | $O(n)$ | $O(n)$ | | 空间复杂度 | $O(d)$(递归深度) | $O(n)$(使用栈存储) | | 最大处理深度 | 受调用栈限制(约1-2万层) | 无限制 | | 输出顺序 | 广度优先 | 深度优先(可通过unshift改为广度优先) | | 适用场景 | 嵌套深度可控的结构 | 超深嵌套结构 | | 保留父节点信息 | 是 | 是 | [^1]: 递归实现参考了形结构遍历的基本模式 [^2]: 迭代法中Map记录父子关系的方法参考了数据结构遍历优化方案
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值