3種解法 - 計算三維形體的表面積


題目

在 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個面暴露的部分累加求和,分別站在每個面前面,從前到後進行求解,當然從算法層面可以對程序進行優化,但爲了代碼可讀性依然保留了寫作初始思路。

  1. 只要有立方體(值大於0),則上下兩個面的值都會暴露
  2. 對於第一排的立方體,暴露的面等於立方體高度(值大小)
  3. 對於後排的立方體,暴露的面等於高出前面立方體的高度(後面值減去當前值)
  • 時間複雜度: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. 上下兩個面的值,僅當立方體大於一個時,在中間的部分才被隱藏了
  2. 第一排的立方體不會被隱藏,對於後排的立方體,隱藏的面等於相交的最小值
  3. 相交的面會減少兩個立方體的暴露,因此一個方向僅需要遍歷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

解法三(按座標減)

思路:跟解法二類似,都是總體面積減去隱藏面積,不過是將座標對應立方體看做一個整體單元,而非解法二中組成立方體的單個小立方體,當然也可以類推,基於解法一思路實現“按座標加”。

  1. 每個座標位置如果沒有任何遮擋,暴露面積爲 4h+2=6h2(h1)4h+2 = 6*h - 2 (h - 1),h爲立方體高度,即grid[i][j]的值
  2. 減去四周被遮擋的面積,每個面被遮擋的面積等於較小的值
  3. 對於等於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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章