文章目錄
題目
在 N * N 的網格上,我們放置一些 1 * 1 * 1 的立方體。
每個值 v = grid[i][j] 表示 v 個正方體疊放在對應單元格 (i, j) 上。
請你返回最終形體的表面積。
示例 1:
輸入:[[2]]
輸出:10
示例 2:
輸入:[[1,2],[3,4]]
輸出:34
示例 3:
輸入:[[1,0],[0,2]]
輸出:16
示例 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
題解
題目本身從描述看理解不太容易,我也是看了10幾遍才理解,簡單解釋下:
示例一:[[2]]
表示在二維平面上,座標爲(0,0)的位置上,有一個高度爲2的立方體
示例 2:[[1,2],[3,4]]
以左下角爲原點(0,0),不同位置表示立方體高度,立方體的排列方式如下:
3 4
1 2
示例 3:[[1,0],[0,2]]
立方體的排列方式如下:
0 2
1 0
示例 4:[[1,1,1],[1,0,1],[1,1,1]]
立方體的排列方式如下:
1 1 1
1 0 1
1 1 1
示例 5:[[2,2,2],[2,1,2],[2,2,2]]
立方體的排列方式如下:
2 2 2
2 1 2
2 2 2
解法一(按立方體加)
思路:對每個座標位置的立方體,對6個面暴露的部分累加求和,分別站在每個面前面,從前到後進行求解,當然從算法層面可以對程序進行優化,但爲了代碼可讀性依然保留了寫作初始思路。
- 只要有立方體(值大於0),則上下兩個面的值都會暴露
- 對於第一排的立方體,暴露的面等於立方體高度(值大小)
- 對於後排的立方體,暴露的面等於高出前面立方體的高度(後面值減去當前值)
- 時間複雜度:O(M*N)
- 空間複雜度:O(1)
# author: [email protected]
class Solution:
def surfaceArea(self, grid: List[List[int]]) -> int:
cnt, m,n = 0, len(grid),len(grid[0])
for i in range(0,m):
for j in range(0,n):
# 上下面
if grid[i][j] > 0:
cnt += 2
# 前面
if i == 0: # 第一排
cnt += grid[i][j]
elif grid[i][j] > grid[i-1][j]:# 後排
cnt += grid[i][j] - grid[i-1][j]
# 後面
if i == m - 1: # 第一排
cnt += grid[i][j]
elif grid[i][j] > grid[i+1][j]: # 後排
cnt += grid[i][j] - grid[i+1][j]
# 左面
if j == 0: # 第一排
cnt += grid[i][j]
elif grid[i][j] > grid[i][j-1]: # 後排
cnt += grid[i][j] - grid[i][j-1]
# 右面
if j == n - 1: # 第一排
cnt += grid[i][j]
elif grid[i][j] > grid[i][j+1]: # 後排
cnt += grid[i][j] - grid[i][j+1]
return cnt
解法二(按立方體減)
思路:對每個座標位置的立方體,減去6個面中被隱藏的部分。
- 上下兩個面的值,僅當立方體大於一個時,在中間的部分才被隱藏了
- 第一排的立方體不會被隱藏,對於後排的立方體,隱藏的面等於相交的最小值
- 相交的面會減少兩個立方體的暴露,因此一個方向僅需要遍歷1次
- 時間複雜度:O(M*N)
- 空間複雜度:O(1)
當然,解法一也可以按照當前的寫法進行改造,相鄰兩個立方體高度差即爲暴露的部分,即前後方向使用:cnt += abs(grid[i][j] - grid[i-1][j])代替解法一中分別對前面和後面的計算。
# author: [email protected]
class Solution:
def surfaceArea(self, grid: List[List[int]]) -> int:
cnt, ov = 0, 0 # cnt:立方體總個數, ov:相交次數
m,n = len(grid),len(grid[0])
for i in range(0,m):
for j in range(0,n):
cnt += grid[i][j]
# 上下面
if grid[i][j] > 1:
ov += grid[i][j] - 1
# 前後 方向
if i > 0:# 後排
ov += min(grid[i][j], grid[i-1][j])
# 左右 方向
if j > 0: # 後排
ov += min(grid[i][j] , grid[i][j-1])
return cnt * 6 - ov * 2
解法三(按座標減)
思路:跟解法二類似,都是總體面積減去隱藏面積,不過是將座標對應立方體看做一個整體單元,而非解法二中組成立方體的單個小立方體,當然也可以類推,基於解法一思路實現“按座標加”。
- 每個座標位置如果沒有任何遮擋,暴露面積爲 ,h爲立方體高度,即grid[i][j]的值
- 減去四周被遮擋的面積,每個面被遮擋的面積等於較小的值
- 對於等於0的座標,面積不存在,直接跳過
- 時間複雜度:O(M*N)
- 空間複雜度:O(1)
# author: [email protected]
class Solution:
def surfaceArea(self, grid: List[List[int]]) -> int:
cnt, m,n = 0, len(grid),len(grid[0])
for i in range(0,m):
for j in range(0,n):
if grid[i][j] <= 0:#當前座標不存在立方體
continue
cnt += 4 * grid[i][j] + 2
if i > 0:# 前面
cnt -= min(grid[i][j], grid[i-1][j])
if i < m - 1:# 後面
cnt -= min(grid[i][j], grid[i+1][j])
if j > 0:# 左面
cnt -= min(grid[i][j], grid[i][j-1])
if j < n - 1:# 右面
cnt -= min(grid[i][j], grid[i][j+1])
return cnt