Leetcode 3311. Construct 2D Grid Matching Graph Layout

1. 解题思路

这一题看起来搞定的人不多,不过多半是因为繁琐吧。

这道题思路上其实非常的直接,就是一个递归的方法,我们可以从连接关系当中快速地找到所有的角节点,边节点以及内部节点,然后通过角节点和边节点,我们可以还原出矩阵的4条边,然后通过内部节点我们可以使用递归的方法求得其构成的内部矩阵,最后我们将得到的4条边拼接到内部矩阵的外侧即可。

整体来说,我们可以将函数抽象为4步:

  1. 找出所有的角节点,边节点以及内部节点
  2. 还原矩阵的边
  3. 计算内部矩阵
  4. 将2中计算得到的边拼接到3中得到的内部矩阵外侧

每一步其实都没有特别复杂,但是会有一些特殊情况,多少会有些复杂和繁琐。比如说:

  1. 找角节点,边节点以及内部节点的时候,通常情况下其度数分别为2、3、4,不过如果矩阵仅一行,那么其对应的度数就是1、2、3,而如果矩阵仅一个点,那么其度数只有1。
  2. 还原矩阵的边的时候,通常矩阵有4条边,每条边除端节点之外均为边节点,且相互间不关联。但是如果矩阵只有1行或者两行,上述说法就会有一点问题,需要单独考虑一下。
  3. 如果矩阵只有1行或者两行,那么他是没有内部矩阵的,因此我们直接对齐矩阵的边然后返回即可;
  4. 拼接矩阵的边的时候,需要首先对齐找到矩阵的4条边的上下左右位置关系,然后进行拼接。

Anyway,总之就是实现上比较复杂,但是整体难度不大,有兴趣的读者可以试试,没兴趣的话这道题pass我觉得也没啥……

2. 代码实现

给出python代码实现如下:

class Solution:
    def constructGridLayout(self, n: int, edges: List[List[int]]) -> List[List[int]]:
        
        def classify_points(points, edges):
            graph = defaultdict(list)
            for u, v in edges:
                graph[u].append(v)
                graph[v].append(u)
            cnt = min(len(graph[u]) for u in points)
            corners = {u for u in points if len(graph[u]) == cnt}
            sides = {u for u in points if len(graph[u]) == cnt+1}
            inners = {u for u in points if len(graph[u]) == cnt+2}
            return graph, corners, sides, inners
        
        def construct_grid_sides(graph, corners, sides):
            if len(sides) == 0:
                u = list(corners)[0]
                grid_sides = [[u, graph[u][0]]]
                if len(graph[u]) > 1:
                    v = graph[u][1]
                    w = [i for i in graph[v] if i != u][0]
                    grid_sides.append([v, w])
                return grid_sides
            elif any(u in corners for c in corners for u in graph[c]):
                u = list(corners)[0]
                v = [i for i in graph[u] if i in corners][0]
                unext = [i for i in graph[u] if i != v][0]
                vnext = [i for i in graph[v] if i != u][0]
                grid_sides = [[u, unext], [v, vnext]]
                u, v = unext, vnext
                while True:
                    unext = [i for i in graph[u] if i != grid_sides[0][-2] and i != v]
                    vnext = [i for i in graph[v] if i != grid_sides[1][-2] and i != u]
                    if len(unext) == 0:
                        break
                    grid_sides[0].append(unext[0])
                    grid_sides[1].append(vnext[0])
                    u, v = unext[0], vnext[0]
            else:
                grid_sides = []
                u0 = list(corners)[0]
                for u in graph[u0]:
                    side = [u0, u]
                    v = [i for i in graph[u] if i in sides and i != side[-2]]
                    while v:
                        u = v[0]
                        side.append(u)
                        v = [i for i in graph[u] if i in sides and i != side[-2]]
                    u = [i for i in graph[u] if i in corners and i != side[-2]][0]
                    side.append(u)
                    grid_sides.append(side)
                    
                    v = [i for i in graph[u] if i != side[-2]]
                    if v:
                        v = v[0]
                        side = [u, v]
                        u = v
                        v = [i for i in graph[u] if i in sides and i != side[-2]]
                        while v:
                            u = v[0]
                            side.append(u)
                            v = [i for i in graph[u] if i in sides and i != side[-2]]
                        u = [i for i in graph[u] if i in corners and i != side[-2]][0]
                        side.append(u)
                        grid_sides.append(side)
            return grid_sides
        
        def merge_grid(graph, grid_sides, inner_grid):
            lu, ld, ru, rd = inner_grid[0][0], inner_grid[-1][0], inner_grid[0][-1], inner_grid[-1][-1]
            for side in grid_sides:
                if lu in graph[side[1]] and ru in graph[side[-2]]:
                    up = side
                    break
                if lu in graph[side[-2]] and ru in graph[side[1]]:
                    up = side[::-1]
                    break
            for side in grid_sides:
                if side[0] == up[0] and side[-1] != up[-1]:
                    left = side
                    break
                if side[-1] == up[0] and side[0] != up[-1]:
                    left = side[::-1]
                    break
            for side in grid_sides:
                if side[0] == up[-1] and side[-1] != up[0]:
                    right = side
                    break
                if side[-1] == up[-1] and side[0] != up[0]:
                    right = side[::-1]
                    break
            for side in grid_sides:
                if side[0] == left[-1] and side[-1] == right[-1]:
                    down = side
                    break
                if side[-1] == left[-1] and side[0] == right[-1]:
                    down = side[::-1]
                    break
            grid = [up] + [[l] + side + [r] for l, side, r in zip(left[1:-1], inner_grid, right[1:-1])] + [down]
            return grid
        
        def construct(points, edges):
            if len(points) <= 1:
                return [list(points)]
            graph, corners, sides, inners = classify_points(points, edges)
            
            grid_sides = construct_grid_sides(graph, corners, sides)
            if len(inners) == 0:
                return grid_sides
            
            inner_edges = [[u, v] for u, v in edges if u in inners and v in inners]
            inner_grid = construct(inners, inner_edges)

            grid = merge_grid(graph, grid_sides, inner_grid)

            return grid
        
        points = [i for i in range(n)]
        return construct(points, edges)

提交代码评测得到:耗时5791ms,占用内存712.5MB。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值