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、付费专栏及课程。

余额充值