三维形体的表面积

        三维形体表面积计算
        在 N * N 的网格上,我们放置一些 1    1    1  的立方体。
        每个值 v  =  grid[i][j] 表示 v 个正方体叠放在对应单元格 (i,  j) 上。
        请你返回最终形体的表面积。

示例  1:
        输入:[[2]]
        输出:10
        意思是在[0,  0]  位置堆叠  2  个立方体
        图示:
2.png

示例  2:
        输入:[[1,2],[3,4]]
        输出:34
        意思是
                在[0,  0]位置堆叠1个立方体,
                在[0,  1]位置堆叠2个立方体,
                在[1,  0]位置堆叠3个立方体,
                在[1,  1]位置堆叠4个立方体
        图示:
1,2, 3,4.png
提示:
        1  <=  N  <=  50
        0  <=  grid[i][j]  <=  50

自我解题思路:
        可以知道每个立方体的三维坐标,且每个立方体本来的表面积都是6,当立方体和其他立方体相邻时,
        就失去了相邻那一面的表面积,立方体表面积应  -1,如果能知道每个立方体被盖住的面数,就能知道总表面积了。
        所以如何判断两个立方体相邻呢?  三维坐标中,其中两个相等,剩下那个位置相差1,则说明两个立方体相邻。
        思路1:  使用一个列表记录每个立方体的三维坐标,之后开始暴力套两层循环,找到每个立方体的相邻的立方体,
                      通过相邻立方体的数量判断需要减去的表面积,从而得出最后的表面积,但这样太耗时了,最后直接超时了。
        思路2:  关键耗时在不绝大不可能相邻的地方找相邻立方体,如果对所有立方体,先按  x,  y,  z  的坐标分好组,
                      等找相邻立方体时,直接去对应的  x  组,y组,z组  找,就更快了。的确会更快,但还是超时了。
        思路3:
                      需要从一堆立方体中找出相邻的,判断相邻也有一定的规则,和  Tow  sum  一样,也就是说,可以通过
                      当前立方体,推测可能存在的相邻立方体坐标(最多6个),然后判断是否在这堆立方体中就可以了。
                      这个方法可行,没有超时了,但时间还是有点长。

def surface_area(grid: List[List[int]]) -> int:
    cubes_num = 0
    cover_area = 0
    cubes_map = dict()
    for x in range(0, len(grid)):
        for y in range(0, len(grid[x])):
            v = grid[x][y]
            for z in range(0, v):
                cubes_map[(x, y, z)] = 6
                cubes_num += 1
                might_adjoin_cubes = [(x, y, z - 1), (x, y - 1, z), (x - 1, y, z)]
                for might_cube in might_adjoin_cubes:
                    if might_cube in cubes_map:
                        cover_area += 2

    return cubes_num * 6 - cover_area

力扣题解思路:
        也是找出所有覆盖的面,最后减去所有覆盖的面积,从而得到所有面积。不一样的是,不是从单个立方体出发考虑的,
        而是以单个“柱体”为单位考虑,分两步走:
                1、计算柱体上下被盖住的面数:取决于柱体包含立方体的数量
                2、计算柱体周围被盖住的面数:这里从柱体出发,只考虑二维坐标,柱体某个方向被盖住的面数取决于
                      该方向相邻柱体的立方体数,min(该方向相邻柱体立方体数,  当前柱体立方体数)  是被盖住的面积。
                      相邻柱体可能有4个方向,可以通过坐标调增得到,但不需要每次都检查4个方向,每个柱体都只检查
                      固定的两个方向就可以了。

剖析:
        自我题解的思路和力扣题解的思路大致一样,只是分析的单位不一样。分析或优化问题时可以试试换单元,
        如单个立方体换成整个柱体考虑

def surface_area2(grid: List[List[int]]) -> int:
    cube_num = 0
    cover_num = 0
    for x in range(0, len(grid)):
        for y in range(0, len(grid[x])):
            cube_num += grid[x][y]
            # 计算堆叠覆盖的面
            cover_num += grid[x][y] - 1 if grid[x][y] else 0
            # 计算相邻柱体覆盖覆盖面积
            if x > 0 and len(grid[x-1]) > y:
                cover_num += min(grid[x - 1][y], grid[x][y])
            if y > 0:
                cover_num += min(grid[x][y - 1], grid[x][y])
    return cube_num * 6 - cover_num * 2