如何查找数组关联元素并将同组值合并为多个子数组?
问题核心本质
你要实现的是无向图连通分量识别:把whoHasMe的每个下标当做独立节点,只要下标j存在于whoHasMe[i]的元素列表中,就认为节点i和j存在连通关系,所有互相连通的节点归为同一组,最终输出所有分组即可。
对于大型数组场景,用并查集(Union-Find,不交集数据结构)实现效率最高,时间复杂度接近线性,完全支持动态变化的输入数组。
实现步骤
- 初始化并查集结构,节点总数等于
whoHasMe的数组长度,每个节点初始的父节点指向自身 - 遍历数组的每个下标
i,遍历whoHasMe[i]存储的所有元素值j,将节点i和节点j执行合并操作 - 所有节点合并完成后,遍历所有下标,按照节点的根节点值做分组,根节点相同的下标归到同一个子数组
- 每个分组内部做升序排序,就得到最终的大数组
可直接运行的代码示例(JavaScript)
function groupConnected(whoHasMe) { const nodeCount = whoHasMe.length; // 并查集初始化 const parent = new Array(nodeCount).fill(0).map((_, idx) => idx); // 查找根节点(带路径压缩) function find(x) { if (parent[x] !== x) { parent[x] = find(parent[x]); } return parent[x]; } // 合并两个节点 function union(x, y) { const rootX = find(x); const rootY = find(y); if (rootX !== rootY) { parent[rootY] = rootX; } } // 遍历所有关联关系执行合并 for (let i = 0; i < nodeCount; i++) { for (const j of whoHasMe[i]) { union(i, j); } } // 按根节点分组 const groupMap = new Map(); for (let i = 0; i < nodeCount; i++) { const root = find(i); if (!groupMap.has(root)) { groupMap.set(root, []); } groupMap.get(root).push(i); } // 每个分组排序后返回 return Array.from(groupMap.values()).map(group => group.sort((a, b) => a - b)); } // 测试用例 const whoHasMe = [[0], [1], [0, 2, 3], [1, 2, 3, 4, 5], [4], [5], [6, 7, 8], [7], [6, 8]]; const finalBigArray = groupConnected(whoHasMe); console.log(finalBigArray); // 输出 [[0,1,2,3,4,5], [6,7,8]],和预期结果完全一致
补充说明
这个方法是通用实现,不管whoHasMe的长度、内部元素怎么动态变化,只要关联规则不变,都能正确输出分组结果。如果数组规模极大(十万级以上节点),可以给并查集加上按秩合并的优化,性能还能进一步提升。
内容的提问来源于stack exchange,提问作者Jay Jay
相关产品推荐
相关产品推荐

