news 2026/8/29 8:33:38

华为OD机试 - SQL记录拆分 - 并查集(Java 新系统 200分)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
华为OD机试 - SQL记录拆分 - 并查集(Java 新系统 200分)

华为OD机试 新系统 题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试(JAVA)真题》。

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

某分布式数据库 Q 系统需要将 SQL 操作日志拆分到多个文件中,现给定一组 SQL 语句输入(数组格式),请按要求将 SQL 语句拆分到不同文件中并返回拆分后的文件数量。拆分规则如下:

  1. 单个数组成员的 SQL 语句(可能包含多条,按;分隔)按同一行完整保存,不可跨文件拆分,且同一行的语句必须在同一个文件中。
  2. 部分语句带事务标签[Tn]n为正整数),如[T1]A;相同事务标签的 SQL 语句必须保存于同一文件中。
  3. 当单个文件保存的行数超出限制时,需要新建文件;按语句组首次出现的行号顺序处理,优先放入当前文件,超出限制则新建文件;
  4. 特殊场景约束:若语句 A 与语句 B 必须同文件,语句 B 与语句 C 必须同文件,则语句 A、B、C 必须在同一文件(约束传递性)。约束合并后语句组计数即便超过限制也必须放在同一文件;
  5. SQL 数组为空时返回 0。

二、输入描述

输入:
参数1:单个文件限定可保存的最大 SQL 语句行数split_line
参数2:SQL 语句数组sql_text,每个数组成员可能包含多条 SQL 语句,用符号;分隔;

三、输出描述

SQL 语句数组按规则拆分后的文件个数。

补充说明:

  • split_line取值范围[1, 10000],无效值返回 0;
  • sql_text每行最多 1000 字符,总语句最多 100000 条;
  • 事务标签的范围[1, 1000]
  • 最后一条语句可以没有分号结尾;
  • 空语句(仅含分号)按 1 行计算。## 四、测试用例

测试用例1:

1、输入

3
[T1]A;
[T2]B;
[T1]C;

2、输出

1

3、说明

第一行同时存在 T1、T2,第二行存在 T1,因此两行属于同一约束组,共 2 行。2 <= 3,只需要 1 个文件。

测试用例2:

1、输入

2
[T1]A;
[T2]B;
[T1]C;
[T2]D;

2、输出

2

3、说明

T1 对应第 1、3 行,共 2 行;T2 对应第 2、4 行,共 2 行。第一个组装满第一个文件,第二个组必须创建第二个文件。

五、解题思路

sql_text中的每个数组成员看作一个“行节点”。同一数组成员无论包含多少个用;分隔的 SQL,都必须完整保存,因此它始终只占 1 行,不需要按分号再次拆分;像;;;这样的空语句所在数组成员同样按 1 行计算。

核心难点是事务标签产生的传递约束。例如第 1 行含[T1],第 2 行同时含[T1][T2],第 3 行含[T2],那么三行必须全部位于同一个文件。这个问题本质上是在求“必须同文件”关系形成的连通分量,因此使用并查集 DSU。

扫描每一行,用正则提取[Tn]。用 HashMap 记录每个事务标签第一次出现的行号;后续再次遇到同一标签时,将当前行和第一次出现的行执行 union。若一行包含多个事务标签,该行会同时参与多个 union,从而自然完成传递合并。

所有事务处理完后,统计每个并查集连通分量包含多少行,即一个不可拆分语句组的大小。

接下来必须按照“语句组首次出现的行号”处理。无需排序:直接再次按照原始行号从前往后扫描,某个并查集根节点第一次被访问时,就代表该语句组第一次出现。然后采用贪心策略:当前文件能完整容纳该组就加入;否则新建文件。若某个组自身行数已经超过 split_line,也不能拆分,仍整体占用一个文件。

时间复杂度约为O(L + N·α(N)),其中 L 为所有 SQL 文本总字符数,N 为数组行数;空间复杂度为O(N + T),T 为事务标签数量。

六、Java算法源码

publicclassOdTest{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);StringfirstLine=scanner.nextLine().trim();intsplitLine=Integer.parseInt(firstLine);List<String>sqlText=newArrayList<>();/* * split_line 后面的每一行都视为 sql_text 的一个数组成员。 * * 这里不能根据 ';' 再拆分,因为题目明确规定: * 一个数组成员中的 SQL 必须作为完整的一行保存。 * * 空白行本身也可以表示一个数组成员。 */while(scanner.hasNextLine()){Stringinput=scanner.nextLine();if(!input.contains(";")){break;}sqlText.add(input);}System.out.println(splitFileCount(splitLine,sqlText));}/** * 并查集: * 用于维护哪些 SQL 行由于事务约束而必须放在同一个文件中。 */privatestaticclassDSU{int[]parent;int[]rank;DSU(intn){parent=newint[n];rank=newint[n];for(inti=0;i<n;i++){parent[i]=i;}}/** * 查找节点所属集合的根节点。 * 使用路径压缩降低后续查询开销。 */intfind(intx){if(parent[x]!=x){parent[x]=find(parent[x]);}returnparent[x];}/** * 合并两个 SQL 行所在的集合。 */voidunion(inta,intb){introotA=find(a);introotB=find(b);if(rootA==rootB){return;}// 按秩合并,避免并查集退化成链表if(rank[rootA]<rank[rootB]){parent[rootA]=rootB;}elseif(rank[rootA]>rank[rootB]){parent[rootB]=rootA;}else{parent[rootB]=rootA;rank[rootA]++;}}}/** * 计算最终需要拆分成多少个文件。 */publicstaticintsplitFileCount(intsplitLine,List<String>sqlText){// split_line 不合法,或者 SQL 数组为空,直接返回 0if(splitLine<1||splitLine>10000||sqlText==null||sqlText.isEmpty()){return0;}intn=sqlText.size();// 每个数组成员都是一个不可拆分的“SQL 行节点”DSUdsu=newDSU(n);/* * key : 事务编号,例如 [T10] 中的 10 * value : 该事务第一次出现在哪一行 * * 后续再次遇到同一个事务时,只需要和第一次出现的行合并。 */Map<Integer,Integer>firstLineByTransaction=newHashMap<>();// 匹配 [T1]、[T23]、[T1000] 等事务标签PatterntagPattern=Pattern.compile("\\[T(\\d+)\\]");for(inti=0;i<n;i++){Stringline=sqlText.get(i);if(line==null){line="";}Matchermatcher=tagPattern.matcher(line);while(matcher.find()){inttag;try{tag=Integer.parseInt(matcher.group(1));}catch(NumberFormatExceptione){continue;}// 题目规定事务标签范围为 [1, 1000]if(tag<1||tag>1000){continue;}IntegerfirstLine=firstLineByTransaction.get(tag);if(firstLine==null){// 当前事务第一次出现firstLineByTransaction.put(tag,i);}else{/* * 同一事务的 SQL 行必须保存在同一个文件中, * 因此将当前行和该事务第一次出现的行合并。 * * 如果当前一行同时出现 [T1]、[T2], * 那么当前行会分别和 T1、T2 对应的行执行 union, * 从而自动完成 A-B、B-C => A-B-C 的传递约束。 */dsu.union(i,firstLine);}}}/* * 统计每个连通分量包含多少个数组成员。 * 每个连通分量就是一个绝对不能拆开的 SQL 语句组。 */int[]groupSize=newint[n];for(inti=0;i<n;i++){introot=dsu.find(i);groupSize[root]++;}/* * 题目要求按照“语句组首次出现的行号”处理。 * * 不需要额外排序: * 直接按照原数组 0、1、2... 顺序扫描, * 某个根节点第一次被遇到的位置, * 天然就是该语句组首次出现的位置。 */boolean[]processed=newboolean[n];intfileCount=0;intusedLines=0;for(inti=0;i<n;i++){introot=dsu.find(i);// 该事务组之前已经处理过if(processed[root]){continue;}processed[root]=true;intsize=groupSize[root];if(fileCount==0){// 第一个语句组创建第一个文件fileCount=1;usedLines=size;}elseif(usedLines+size<=splitLine){/* * 当前文件能够完整容纳整个语句组, * 根据题目“优先放入当前文件”的要求直接加入。 */usedLines+=size;}else{/* * 当前文件装不下整个组,只能创建新文件。 * * 注意:如果 size 本身已经大于 splitLine, * 根据题目规则也不能拆分,仍然整体放进一个新文件。 */fileCount++;usedLines=size;}}returnfileCount;}}

七、效果展示

1、输入

2
;
A;
;;
B;
C;

2、输出

3

3、说明

共有 5 个数组成员,每个成员都按 1 行计算。; 和 ;; 虽然是空语句,但所在数组成员仍然占 1 行。每个文件最多 2 行,因此需要 2 + 2 + 1,共 3 个文件。


🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 新系统 200分)

🏆本专栏收录于《华为OD机试(JAVA)真题》。

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 8:32:12

数学建模中Matplotlib进阶:从基础绘图到专业可视化

1. 从“能画”到“画好”&#xff1a;数学建模中的Matplotlib进阶之路 如果你参加过数学建模比赛&#xff0c;或者处理过任何需要数据可视化的科研、分析任务&#xff0c;大概率用过Matplotlib。这个Python绘图库的名气太大了&#xff0c;大到很多人觉得“作图”就等于 import…

作者头像 李华
网站建设 2026/8/29 8:31:39

谷歌浏览器下载安装全指南:版本选择、配置优化与故障排查

搜索“谷歌浏览器下载安装”的人&#xff0c;很多时候并不是第一次下载浏览器&#xff0c;而是已经卡在某个具体环节上了&#xff1a;电脑还是 Windows 7&#xff0c;装不了网站首页推荐的最新版&#xff1b;点击在线安装包下载了半天&#xff0c;最后却提示安装失败&#xff1…

作者头像 李华
网站建设 2026/8/29 8:28:41

如何用Godot做雨天粒子?5步搭出雨滴与水花的完整参数指南

如何用Godot做雨天粒子&#xff1f;5步搭出雨滴与水花的完整参数指南 【免费下载链接】godot Godot Engine – Multi-platform 2D and 3D game engine 项目地址: https://gitcode.com/GitHub_Trending/go/godot Godot 的雨天粒子效果核心在于两类节点的组合&#xff1a;…

作者头像 李华
网站建设 2026/8/29 8:27:38

飞行力学大作业全流程解析:从建模到仿真与报告撰写

简介&#xff1a;飞行力学是研究飞行器在外力作用下运动规律的核心学科&#xff0c;其本质是将物理问题转化为数学模型&#xff0c;并通过数值方法求解。这一过程涉及动力学建模、坐标系定义、运动方程推导等基础概念。在工程实践中&#xff0c;MATLAB/Simulink和Python等工具被…

作者头像 李华
网站建设 2026/8/29 8:24:46

Hermes Agent 智能交易 4 步上手:从行情接入到自动落单

Hermes Agent 智能交易 4 步上手&#xff1a;从行情接入到自动落单 【免费下载链接】hermes-agent The agent that grows with you 项目地址: https://gitcode.com/GitHub_Trending/he/hermes-agent 凌晨两点&#xff0c;币价插针&#xff0c;手机却安静地躺在枕边——这…

作者头像 李华
网站建设 2026/8/29 8:23:18

Ant Design 紧凑模式完整指南:3 步搞定高密度布局

Ant Design 紧凑模式完整指南&#xff1a;3 步搞定高密度布局 【免费下载链接】ant-design An enterprise-class UI design language and React UI library 项目地址: https://gitcode.com/GitHub_Trending/an/ant-design Ant Design 紧凑模式分两级&#xff1a;Space.C…

作者头像 李华