三维形体表面积计算
在 N * N 的网格上,我们放置一些 1 1 1 的立方体。
每个值 v = grid[i][j] 表示 v 个正方体叠放在对应单元格 (i, j) 上。
请你返回最终形体的表面积。
示例 1:
输入:[[2]]
输出:10
意思是在[0, 0] 位置堆叠 2 个立方体
图示:
示例 2:
输入:[[1,2],[3,4]]
输出:34
意思是
在[0, 0]位置堆叠1个立方体,
在[0, 1]位置堆叠2个立方体,
在[1, 0]位置堆叠3个立方体,
在[1, 1]位置堆叠4个立方体
图示:
提示:
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