【力扣roadmap】2088. 统计农场中肥沃金字塔的数目

20 阅读2分钟

题目描述

  • 竞赛积分2105

image.png

思路

审题: 题目要求计算一个矩阵中的正金字塔和倒金字塔的总数目。

显然正金字塔和倒金字塔没什么不同,我们可以先思考正金字塔怎么做,然后倒过来同理炮制就是倒金字塔数目。

通过规模猜算法,行n和列m都在1000范围,所以大胆来猜dp来做。

小金字塔和大金字塔的状态转移也是很好想的

dp=griddp = grid
dp[r][c]=min(dp[r+1][c1],dp[r+1][c],dp[r+1][c+1])+1dp[r][c] = min(dp[r+1][c-1],dp[r+1][c],dp[r+1][c+1]) + 1

上面公式的含义是,dp[r][c]表示以r行c列元素为正金字塔顶点的时候,合法正金字塔的最大高度。用题目给定的矩阵网格初始化dp数组,dp[r][c]通过其下面的网格状态转移而来,是下面最小金字塔高度+1(注意当dp[r][c]==1的时候才进行状态转移)。

然后你会发现,以r行c列元素为正金字塔顶点的时候,贡献的合法正金字塔的数量等于最大高度dp[r][c]-1。 而且dp[r][c]需要其下一行的状态才能得到,因此需要以行为单位倒着枚举,并且第0列和最后一列永远不会出现金字塔的塔尖,所以枚举列的时候从1到m-1(闭区间)即可。

代码

class Solution:
    def countPyramids(self, grid: List[List[int]]) -> int:
        # 以cell[r][c]为顶点且高度为h的pyramid,贡献h-1个pyramids
        # 先计算正金字塔
        n , m = len(grid) , len(grid[0])
        dp = deepcopy(grid)
        ans = 0 
        for r in range(n-2,-1,-1) :
            for c in range(1,m-1) :
                if dp[r][c] == 1 :
                    dp[r][c] = min( dp[r+1][c-1] , dp[r+1][c] , dp[r+1][c+1]) + 1 
                    ans += dp[r][c] - 1 
        # # 计算倒金字塔
        dp = deepcopy(grid)
        for r in range(1,n):
            for c in range(1,m-1) :
                if grid[r][c] == 1 :
                    dp[r][c] = min( dp[r-1][c-1] , dp[r-1][c] , dp[r-1][c+1]) + 1 
                    ans += dp[r][c] - 1 
        return ans