LC1277. 统计全为 1 的正方形子矩阵

本文解析如何利用动态规划解决给定矩阵中1组成的正方形子矩阵计数问题,通过实例演示dp数组的更新过程,并提供了一段优化后的代码实现。核心在于理解以每个单元格为右下角的正方形最大边长计算方法。

LC1277. 统计全为 1 的正方形子矩阵

给你一个 m * n 的矩阵,矩阵中的元素不是 0 就是 1,请你统计并返回其中完全由 1 组成的 正方形 子矩阵的个数。

示例 :

输入:matrix =
[
  [0,1,1,1],
  [1,1,1,1],
  [0,1,1,1]
]
输出:15

解释:
边长为 1 的正方形有 10 个。
边长为 2 的正方形有 4 个。
边长为 3 的正方形有 1 个。
正方形的总数 = 10 + 4 + 1 = 15.

解法参考LC221,
dp[i][j]=x表示以(i,j)​​​ 为右下角的正方形的最大边长为 x​,等价于以 (i, j)​ 为右下角的正方形数目为 x。

结果统计正方形个位数,则res+=dp[i][j];

注意定义边界时,matrix[0][0]统计一次就好了

class Solution {
    public int countSquares(int[][] matrix) {

        int m=matrix.length;
        int n=matrix[0].length;
        int res=0;

        int dp[][]=new int[m][n];
        for(int i=0;i<m;i++){
            dp[i][0]=matrix[i][0];
             res+=dp[i][0];
        }
        //matrix[0][0]已经统计过了
        for(int i=1;i<n;i++){
            dp[0][i]=matrix[0][i];
             res+=dp[0][i];
        }

        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                if(matrix[i][j]==0){
                    dp[i][j]=0;
                }else{
                    dp[i][j]= Math.min(Math.min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
                }
                res+=dp[i][j];
            }
        }
        return res;
    }
}
基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样与统计,通过模拟系统元件的故障与修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构与设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码与案例分析,便于复现和扩展应用。; 适合人群:具备电力系统基础知识和Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行与可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理与实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估与优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
<think>首先,用户的问题是关于统计一个 m×n 的二进制矩阵中所有完1组成的正方形子矩阵的数量。这是一个常见的动态规划问题。 我需要回忆一下动态规划解决方案。关键思想是使用一个动态规划数组 dp,其中 dp[i][j] 表示以位置 (i, j) 为右下角的最大正方形的边长,同时它也代表了以 (i, j) 为右下角的正方形子矩阵的数量(因为边长为 k 的正方形包含了边长为 1 到 k 的所有正方形)。 递推公式是: - 如果 matrix[i][j] == '0',则 dp[i][j] = 0,因为没有正方形可以以0结束。 - 如果 matrix[i][j] == '1',则 dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1。这是因为正方形的边长受限于上方、左方和左上方的最小边长。 然后,总和就是所有 dp[i][j] 的值之和,因为每个 dp[i][j] 表示以 (i,j) 为右下角的正方形数量。 现在,我需要根据系统级指令来构建回答: - 所有行内数学表达式使用 $...$ 格式。 - 独立公式使用 $$...$$ 格式。 - 使用中文回答。 - 生成相关问题。 - 在引用的段落末尾添加引用标识。 用户提供了几个引用,我应该参考它们: - 引用[1] 提到时间复杂度 O(mn * min(m,n)),空间复杂度 O(mn)。 - 引用[2] 给了一个例子。 - 引用[3] 和 [4] 讨论了动态规划方法。 在我的回答中,我需要结构化: 1. 解释问题。 2. 描述动态规划方法。 3. 给出递推公式。 4. 讨论时间和空间复杂度。 5. 提供一个例子或代码(可选)。 6. 生成相关问题。 最后,添加相关问题。 步骤: 1. 介绍问题。 2. 详细解释动态规划解决方案。 3. 给出公式。 4. 分析复杂度。 5. 生成相关问题。 使用中文。</think>### 统计二进制矩阵中完1 组成的正方形子矩阵数量 要统计一个 $m \times n$ 的二进制矩阵中所有完1 组成的正方形子矩阵的数量,这是一个经典的动态规划问题。下面我将逐步解释解决方案,确保回答清晰可靠。核心思路是使用动态规划数组 `dp`,其中 `dp[i][j]` 表示以位置 $(i, j)$ 为右下角的最大正方形边长,同时也表示以 $(i, j)$ 为右下角的正方形子矩阵的数量(因为边长从 1 到 `dp[i][j]` 的正方形各一个)。最后,所有 `dp[i][j]` 的和就是总数量。 #### 动态规划方法 1. **问题定义**: - 输入:一个 $m \times n$ 的二进制矩阵 `matrix`,其中每个元素为 '0' 或 '1'。 - 输出:完1 组成的正方形子矩阵的总数。 - 例如,矩阵 $\begin{bmatrix} 1 & 0 & 1 \\ 1 & 1 & 0 \\ 1 & 1 & 0 \end{bmatrix}$ 中,有 6 个边长为 1正方形1 个边长为 2 的正方形,总数为 7[^2]。 2. **动态规划数组定义**: - 设 `dp[i][j]` 为以 $(i, j)$ 为右下角的最大正方形边长。 - 同时,`dp[i][j]` 也表示以 $(i, j)$ 为右下角的正方形子矩阵数量(即边长为 1 到 `dp[i][j]` 的正方形各一个)[^4]。 3. **递推公式**: - 如果 `matrix[i][j] == '0'`,则 `dp[i][j] = 0`(因为右下角是 0 时无法形成有效正方形)。 - 如果 `matrix[i][j] == '1'`,则 `dp[i][j]` 取决于其上方、左方和左上方的值: $$ \text{dp}[i][j] = \min(\text{dp}[i-1][j], \text{dp}[i][j-1], \text{dp}[i-1][j-1]) + 1 $$ 这个公式表示,以 $(i, j)$ 为右下角的正方形边长受限于其相邻位置的最小边长(因为正方形需要所有方向都满足条件)[^4]。 - 最终,总正方形数量为所有 `dp[i][j]` 的和: $$ \text{总数} = \sum_{i=0}^{m-1} \sum_{j=0}^{n-1} \text{dp}[i][j] $$ 4. **初始化**: - 对于第一行($i = 0$)和第一列($j = 0$),`dp[i][j]` 直接等于 `matrix[i][j]`(因为边界位置只能形成边长为 1正方形)。 - 例如,如果 `matrix[0][0] = '1'`,则 `dp[0][0] = 1`;如果 `matrix[0][0] = '0'`,则 `dp[0][0] = 0`[^4]。 5. **算法步骤**: - 初始化一个 $m \times n$ 的 `dp` 数组,所有元素为 0。 - 遍历矩阵的每个位置 $(i, j)$: - 如果 $i = 0$ 或 $j = 0$,则 `dp[i][j] = int(matrix[i][j])`。 - 否则,如果 `matrix[i][j] == '1'`,则 `dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1`。 - 如果 `matrix[i][j] == '0'`,则 `dp[i][j] = 0`。 - 计算总和:`total = sum(dp[i][j] for all i, j)`。 6. **复杂度分析**: - **时间复杂度**:$O(mn)$,因为需要遍历整个矩阵一次。每个位置的计算是常数时间。 - **空间复杂度**:$O(mn)$,用于存储 `dp` 数组。如果优化空间,可以降到 $O(n)$(只存储当前行和上一行),但通常 $O(mn)$ 更直观[^1][^4]。 7. **示例代码(Python)**: ```python def countSquares(matrix): if not matrix: return 0 m, n = len(matrix), len(matrix[0]) dp = [[0] * n for _ in range(m)] total = 0 for i in range(m): for j in range(n): if matrix[i][j] == '1': if i == 0 or j == 0: dp[i][j] = 1 else: dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1 total += dp[i][j] return total # 示例输入 matrix = [ ['1', '0', '1'], ['1', '1', '0'], ['1', '1', '0'] ] print(countSquares(matrix)) # 输出: 7 ``` #### 注意事项 - 这个方法高效且可靠,已在 LeetCode 1277 题中验证[^1][^2][^4]。 - 如果矩阵很大,优化空间复杂度到 $O(n)$ 是可行的(通过只保留两行数组),但代码会更复杂。 - 动态规划的核心是理解递推公式:它保证了每个 `dp[i][j]` 正确计数以 $(i, j)$ 为右下角的所有正方形[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值