892. 三维形体的表面积
在 N N 的网格上,我们放置一些 1 1 * 1 的立方体。 每个值 v = grid[i][j] 表示 v 个正方体叠放在对应单元格 (i, j) 上。 请你返回最终形体的表面积。
示例 1:
示例 2:
示例 3:
示例 4:
输入:[[1,1,1],[1,0,1],[1,1,1]]
输出:32
示例 5:
输入:[[2,2,2],[2,1,2],[2,2,2]]
输出:46
提示:
1 <= N <= 50
0 <= grid[i][j] <= 50
方法一:分步累加
思路
- 我们单独计算每一个
v = grid[i][j]所贡献的表面积,再将所有的v值相加就能得到最终形体的表面积: - 对于顶面和底面的表面积,如果
v > 0,那么顶面和底面各贡献了 1 的表面积,总计 2 的表面积; - 对于四个侧面的表面积,只有在相邻位置的高度小于
v时,对应的那个侧面才会贡献表面积,且贡献的数量为v - nv,其中nv是相邻位置的高度。我们可以将其写成max(v - nv, 0)。
举一个例子,对于网格
1 5
6 7
而言,位置 grid[0][1] 的高度为 5:
- 因为 5 > 0,所以贡献了 2 的顶面和底面表面积;
- 该位置的上方和右侧没有单元格,可以看成高度为 0,所以分别贡献了
max(5 - 0, 0) = 5的表面积; - 该位置的左侧高度为 1,所以贡献了
max(5 - 1, 0) = 4的表面积; - 该位置的下方高度为 7,所以贡献了
max(5 - 7, 0) = 0的表面积。
因此 grid[0][1] 贡献的表面积总和为 2 + 5 + 5 + 4 + 0 = 16。
算法
对于每个 v = grid[r][c] > 0 ,计算 ans += 2 ,对于 grid[r][c] 四个方向的每个相邻值 nv 还要加上 max(v - nv, 0) 。
class Solution {public int surfaceArea(int[][] grid) {int[] dr = new int[]{0, 1, 0, -1};int[] dc = new int[]{1, 0, -1, 0};int N = grid.length;int ans = 0;for (int r = 0; r < N; ++r)for (int c = 0; c < N; ++c)if (grid[r][c] > 0) {ans += 2;for (int k = 0; k < 4; ++k) {int nr = r + dr[k];int nc = c + dc[k];int nv = 0;if (0 <= nr && nr < N && 0 <= nc && nc < N)nv = grid[nr][nc];ans += Math.max(grid[r][c] - nv, 0);}}return ans;}}
方法二:
思路
看看有多少个立方体,总表面积是立方体的数量 × 6,但是因为相邻的会互相盖住,统计一下被盖住的面,然后减去被盖住的面就行了。
class Solution {public int surfaceArea(int[][] grid) {if(grid == null || grid.length < 1 || grid[0].length < 1) return 0;//统计所有的立方体数量int blocks = 0;//统计有多少个面被其他面盖住,那么就在所有的立方体的表面积上减去被盖住的面数×2(因为盖住一个面需要另一个面来盖,所以会损失2个面);int cover = 0;for(int i = 0;i < grid.length;++i) {for(int j = 0; j < grid[0].length;++j) {blocks += grid[i][j];//这个是统计当前格子中因为堆叠而盖住了几个面cover += grid[i][j] > 1 ? grid[i][j] -1 : 0;if(i > 0) {//看看上一行同一列盖住了多少个面cover += Math.min(grid[i-1][j],grid[i][j]);}if(j > 0) {//看看同一行前一列盖住了几个面cover += Math.min(grid[i][j-1],grid[i][j]);}}}return blocks * 6 - cover * 2;}}
