当前位置: 首页 > web >正文

行政区划编码树形题解

行政区划编码树形题解

题目描述

将一维的中国行政区划编码数组转换为树形结构,处理直辖市等特殊层级跳跃情况。

输入数据特点

const codes = [// === 北京市(直辖市,省级) ==={code: "110000",name: "北京市",},{code: "110101",name: "东城区",},{code: "110102",name: "西城区",},{code: "110105",name: "朝阳区",},{code: "110106",name: "丰台区",},{code: "110107",name: "石景山区",},{code: "110108",name: "海淀区",},{code: "110109",name: "门头沟区",},{code: "310000",name: "上海市",},{code: "310101",name: "黄浦区",},{code: "310104",name: "徐汇区",},{code: "310105",name: "长宁区",},{code: "310106",name: "静安区",},{code: "310107",name: "普陀区",},{code: "310109",name: "虹口区",},{code: "310110",name: "杨浦区",},// === 河北省(普通省份,省 → 市 → 区) ==={code: "130000",name: "河北省",},{code: "130100",name: "石家庄市",},{code: "130102",name: "长安区",},{code: "130104",name: "桥西区",},{code: "130200",name: "唐山市",},{code: "130202",name: "路北区",},{code: "130203",name: "路南区",},
];

数据规律分析

编码规则:

  • xx0000:省级/直辖市级(如110000北京市、130000河北省)
  • xx0100:市级(如130100石家庄市)
  • xx0101:区县级(如130102长安区)

特殊情况:

  • 直辖市跳层110000北京市 → 110101东城区(跳过了市级)
  • 标准层级130000河北省 → 130100石家庄市 → 130102长安区

预期输出结构

转换后应该得到如下树形结构:

[{"code": "110000","name": "北京市","children": [{"code": "110101", "name": "东城区"},{"code": "110102", "name": "西城区"},{"code": "110105", "name": "朝阳区"},{"code": "110106", "name": "丰台区"},{"code": "110107", "name": "石景山区"},{"code": "110108", "name": "海淀区"},{"code": "110109", "name": "门头沟区"}]},{"code": "310000","name": "上海市","children": [{"code": "310101", "name": "黄浦区"},{"code": "310104", "name": "徐汇区"},{"code": "310105", "name": "长宁区"},{"code": "310106", "name": "静安区"},{"code": "310107", "name": "普陀区"},{"code": "310109", "name": "虹口区"},{"code": "310110", "name": "杨浦区"}]},{"code": "130000","name": "河北省","children": [{"code": "130100","name": "石家庄市","children": [{"code": "130102", "name": "长安区"},{"code": "130104", "name": "桥西区"}]},{"code": "130200","name": "唐山市","children": [{"code": "130202", "name": "路北区"},{"code": "130203", "name": "路南区"}]}]}
]

算法核心挑战

  1. 父子关系识别:根据编码规律找到每个节点的父节点
  2. 跳层处理:直辖市的区直接隶属于直辖市,跳过市级
  3. 缺失层级处理:当直接父节点不存在时,需要向上查找

解决方案一:本人事后实现(略显丑陋)

// 下面是本人事后写的代码  有点烂说是哈
const roots = [];
const getParent = (code) => {switch (true) {case code.endsWith("0000"):return null;case code.endsWith("00"):return code.slice(0, 2) + "0000";default:return code.slice(0, 4) + "00";}
};const codeMap = new Map(codes.map((value) => [value.code, value]));for (let element of codes) {const { code } = element;const node = codeMap.get(code);const pcode = getParent(code);if (pcode === null) {roots.push(node);} else {if (codeMap.has(pcode)) {const pnode = codeMap.get(pcode);const pnodeChildren = pnode?.children;Array.isArray(pnodeChildren)? pnodeChildren.push(node): (pnode.children = [node]);} else {let gcode = getParent(pcode);const gnode = codeMap.get(gcode);const gnodeChildren = gnode?.children;Array.isArray(gnodeChildren)? gnodeChildren.push(node): (gnode.children = [node]);}}
}console.log(JSON.stringify(roots));

算法分析

优点:

  • 直接处理跳层情况,当直接父节点不存在时,查找祖父节点
  • 使用Map提高查找效率
  • 逻辑相对直观

缺点:

  • 只能处理跳一层的情况,如果跳多层会有问题
  • 代码相对冗长,有重复逻辑
  • children数组初始化逻辑复杂

解决方案二:GPT优化版本

// GPT优化后  其实我们无需判断这个垃圾的
const removeEmptyArray = (array) => {for (let element of array) {if (element.children.length === 0) {delete element.children;} else {removeEmptyArray(element.children);}}
};const buildTree = () => {const map = new Map(codes.map((value) => [value.code, { ...value, children: [] }]));const roots = [];for (let code of map.values()) {const codeString = code.code;let pcode = getParent(codeString);while (pcode && !map.has(pcode)) {pcode = getParent(pcode); //一直往上面找就完了}if (pcode === null) {roots.push(code);} else {const pnode = map.get(pcode);pnode.children.push(code);}}removeEmptyArray(roots);return JSON.stringify(roots);
};console.log("GPT优化的代码", buildTree());

优化亮点

改进之处:

  1. 通用的跳层处理:使用while循环一直向上查找,可以处理任意层级的跳跃
  2. 预初始化children:所有节点预先创建空的children数组,避免条件判断
  3. 统一的处理逻辑:不需要区分是否存在父节点的情况
  4. 清理空数组:最后移除空的children属性,保持输出干净

核心改进:

// 原版:只能跳一层
if (codeMap.has(pcode)) {// 处理直接父节点
} else {let gcode = getParent(pcode); // 只处理祖父节点// ...
}// 优化版:可以跳任意层
while (pcode && !map.has(pcode)) {pcode = getParent(pcode); // 一直往上找
}

算法复杂度分析

时间复杂度

  • 原版:O(n),每个节点处理一次
  • 优化版:O(n×k),其中k是最大跳层数,实际场景下k很小,近似O(n)

空间复杂度

  • 两版本都是:O(n),需要存储所有节点的Map和最终的树结构

总结

两种解决方案都正确处理了行政区划编码的树形转换问题,主要区别在于:

  1. 通用性:优化版可以处理任意层级跳跃,原版只能处理单层跳跃
  2. 代码简洁性:优化版逻辑更统一,代码更简洁
  3. 性能:在实际数据场景下性能差异很小

这个问题很好地展示了如何处理真实世界中数据不规整的情况,是一个很有实际价值的算法问题。

http://www.xdnf.cn/news/20513.html

相关文章:

  • 09_多态
  • `IntersectionObserver`延迟加载不在首屏的自动播放视频/图片/埋点/
  • Boost电路:稳态和小信号分析
  • Linux匿名管道和命名管道以及共享内存
  • C++并发编程指南 递归锁 介绍
  • Kimi K2-0905 256K 上下文 API 状态管理优化教程
  • 2.虚拟内存:分页、分段、页面置换算法
  • 分享一个基于Python+大数据的房地产一手房成交数据关联分析与可视化系统,基于机器学习的深圳房产价格走势分析与预测系统
  • Embedding上限在哪里?- On the Theoretical Limitations of Embedding-Based Retrieval
  • AI产品经理面试宝典第86天:提示词设计核心原则与面试应答策略
  • 《sklearn机器学习——聚类性能指标》Calinski-Harabaz 指数
  • Wisdom SSH 是一款搭载强大 AI 助手的工具,能显著简化服务器配置管理流程。
  • SSH服务远程安全登录
  • Linux系统shell脚本(四)
  • CodeSandbox Desktop:零配置项目启动工具,实现项目环境隔离与Github无缝同步
  • AI大模型应用研发工程师面试知识准备目录
  • 苍穹外卖优化-续
  • Java包装类型
  • Git 长命令变短:一键设置别名
  • Linux以太网模块
  • 【嵌入式】【科普】AUTOSAR学习路径
  • 《无畏契约》游戏报错“缺少DirectX”?5种解决方案(附DirectX修复工具)
  • 基于单片机智能行李箱设计
  • 云手机运行流畅,秒开不卡顿
  • 无拥塞网络的辩证
  • 24.线程概念和控制(一)
  • 贪心算法应用:数字孪生同步问题详解
  • B.50.10.10-微服务与电商应用
  • 关于退耦电容
  • 【LeetCode热题100道笔记】将有序数组转换为二叉搜索树