Java 中计算所有元素的子矩阵2025年5月12日 | 阅读 8 分钟 计算全为 1 的子矩阵数量是在编程中一个常见的问题,它涉及到在给定的 二进制 矩阵(仅包含 0 和 1)中,找到所有元素都为 1 的子矩阵的数量。这个问题广泛应用于图像处理、数据分析和优化问题。给定一个 m x n 的二进制矩阵,我们的任务是计算所有可能的只包含 1 的子矩阵。 示例示例 1 输入 矩阵 = 1 1 1 1 输出:全为 1 的子矩阵总数:9 解释 在这种情况下,给定的矩阵由 1 组成,允许我们形成多个子矩阵。我们可以计算每个单独的 1x1 子矩阵,这贡献了四个。此外,我们可以形成 1x2 的水平子矩阵和 2x1 的垂直子矩阵,每个子矩阵出现两次。最后,整个 2x2 子矩阵也是有效的。将所有可能的子矩阵相加,我们得到 4 + 2 + 2 + 1 = 9。 示例 2 输入 矩阵 = 1 0 1 1 1 1 1 1 1 输出:全为 1 的子矩阵总数:24 解释 对于这个 3x3 的矩阵,所有元素都是 1,这意味着我们可以形成大量的有效子矩阵。我们从计算所有 1x1 的子矩阵开始,这为总数贡献了 **9**。转向稍大的子矩阵,1x2 的水平子矩阵和 2x1 的垂直子矩阵各贡献 6,因为它们可以形成在不同的位置。接下来,可以计算 2x2 的子矩阵,贡献 4 个。此外,1x3 的水平子矩阵和 3x1 的垂直子矩阵各出现 3 次。最后,整个 3x3 的矩阵本身也算作一个有效的子矩阵,为总数增加一个。将所有可能的子矩阵相加,我们得到 24。 示例 3 输入 矩阵 = 1 1 1 1 1 1 1 1 输出:全为 1 的子矩阵总数:30 解释 2x4 的矩阵只包含 1,允许形成许多可能的子矩阵。首先,每个 1x1 的子矩阵贡献 8 个。转向更大的水平子矩阵,1x2 的子矩阵出现 6 次,而 1x3 的子矩阵出现 4 次,1x4 的子矩阵出现 2 次。 由于矩阵有两行,因此垂直子矩阵也需要考虑,2x1 的子矩阵出现 4 次。此外,2x2 的子矩阵可以以 3 种不同的方式形成,2x3 的子矩阵可以以 2 种方式形成,最后,整个 2x4 的矩阵本身是一个有效的子矩阵,为总数增加一个。将所有可能的子矩阵加在一起,我们得到总共 30 个。 使用暴力方法算法步骤 1:首先确定给定二进制矩阵的行数和列数。初始化一个变量来跟踪只包含 1 的子矩阵的数量。 步骤 2:使用嵌套循环迭代所有可能的起始位置 (i, j),它们代表潜在子矩阵的左上角。 步骤 3:对于每个选择的左上角,然后迭代所有可能的结束位置 (x, y),它们代表子矩阵的右下角。 步骤 4:提取由 (i, j) 作为左上角和 (x, y) 作为右下角定义的子矩阵的元素,并检查此范围内的所有元素是否都为 1。 步骤 5:如果在验证过程中在子矩阵中找到 0,则将其丢弃并移动到下一个可能的子矩阵。否则,增加计数,因为这是一个有效的子矩阵。 步骤 6:继续此过程,处理给定矩阵中的所有可能子矩阵,确保考虑所有有效的配置。 步骤 7:所有迭代完成后,返回只包含 1 的有效子矩阵的总数。 实施输出 Example 1 Output: 9 Example 2 Output: 24 Example 3 Output: 30 复杂度分析时间复杂度 在最坏的情况下,时间复杂度为 O(n⁶),因为它涉及迭代所有可能的左上角 O(n²),所有可能的右下角 O(n²),并在此处检查每个子矩阵是否全为 1,这可能需要 O(n²) 的操作,导致 O(n²) * O(n²) * O(n²) = O(n⁶)。 空间复杂度 空间复杂度为 O(1),因为该算法仅使用几个 整数 变量,并且除了输入矩阵之外不需要额外的内存。 使用递归算法步骤 1:确定给定二进制矩阵的行数和列数,并初始化一个计数器来跟踪有效子矩阵。 步骤 2:通过循环遍历矩阵中的每个元素来迭代所有可能的子矩阵左上角。 步骤 3:从每个左上角扩展到所有可能的右下角,这有效地生成了每个可能的子矩阵。 步骤 4:对于每个子矩阵,通过迭代其元素来检查它是否只包含 1。 步骤 5:如果在验证过程中发现 0,则丢弃该子矩阵并移至下一个;否则,增加计数器。 步骤 6:重复此过程,直到检查完所有可能的子矩阵,并确保考虑所有有效的配置。 步骤 7:检查完所有子矩阵后,返回最终计数。 实施 输出 Example 1 Output: 9 Example 2 Output: 24 Example 3 Output: 30 复杂度分析时间复杂度 在最坏的情况下,时间复杂度为 O(n⁴),因为选择所有左上角需要 O(n²),选择右下角需要 O(n²),检查子矩阵需要 O(n²),从而得到 O(n⁴)。 空间复杂度 空间复杂度为 O(1),因为只使用了几个整数变量,而没有额外的 数据结构。 使用动态规划算法步骤 1:创建一个 二维数组 来存储每个单元格结束的子矩阵数量,并初始化一个变量来跟踪总计数。 步骤 2:遍历矩阵中的每个单元格。如果单元格的值为 1,则使用先前行和列的值计算以该位置结束的子矩阵的数量。 步骤 3:如果单元格位于第一行和第一列,则将其计为一个子矩阵。 步骤 4:如果单元格位于第一行,则将先前列的计数加到当前计数上,因为它只能水平扩展。 步骤 5:如果单元格位于第一列,则将先前行的计数加到当前计数上,因为它只能垂直扩展。 步骤 6:对于其他位置,通过考虑来自上方单元格、左侧单元格和对角相邻单元格的贡献来计算子矩阵,同时避免重复计数。 步骤 7:将为每个单元格计算的子矩阵累加到总计数中,并在处理完所有元素后返回最终计数。 实施输出 Example 1 Output: 9 Example 2 Output: 24 Example 3 Output: 30 复杂度分析时间复杂度 此方法的 time complexity 为 O(m × n),因为矩阵中的每个单元格都只处理一次,其值根据先前计算的相邻单元格的值来确定。不需要对子矩阵进行嵌套迭代,这使其比暴力方法效率更高。 空间复杂度 space complexity 为 O(m × n),因为使用了一个与输入矩阵大小相同的额外二维数组来存储中间结果。它允许高效的计算,但需要与矩阵维度成比例的额外内存。 下一主题Java 中的宇宙超类 |
在 Java 中,Vaadin 框架是一个用于开发 Web 应用程序的开源框架。由于它同时支持 JavaScript 和 AJAX,因此我们可以使用它们。通过使用 Google Web Toolkit,我们可以将其包含外部功能。Vaadin 框架渲染丰富的...
5 分钟阅读
我们对互联网的依赖日益增加,我们与他人分享大量个人信息。由于我们的数据或个人信息不安全。为此,数据的安全性对我们变得至关重要。我们需要保守数据机密,...
阅读 6 分钟
问题陈述 N 条凶猛的鱼沿着一条河流游泳。每条鱼都有重量和前进方向。代表河流的一维数组中的每个成员都是一条鱼。鱼可以逆流而上或顺流而下。大鱼会吞噬小鱼...
5 分钟阅读
超级素数是素数序列中占据素数位置的素数。例如,在列表 {2, 3, 5, 7, 11} 中,第二个素数 (3) 和第三个素数 (5) 是超级素数。识别超级素数涉及两者...
阅读9分钟
在本节中,我们将学习什么是迷人数字,并创建 Java 程序来检查给定数字是否迷人。迷人数字程序经常在 Java 编码测试中出现。迷人数字将一个数字分别乘以二和三,...
阅读 3 分钟
main 方法是执行 Java 代码的起点。如果在运行时 JVM 找不到 main 方法,将抛出运行时异常。换句话说,如果 Java 代码中不存在 main 方法,JVM 将报告错误……
阅读 6 分钟
顾名思义,常量是编程中一个不变的实体。换句话说,它的值不能被改变。通常,为了实现这一点,变量会使用 final 关键字声明。常量经常用于表示稳定的值,例如数学...
阅读 6 分钟
在本节中,我们将讨论 Java 中字符串的最大大小是多少。在 Java 中,字符串可以看作是字符数组,字符序列称为字符串。String 类表示字符字符串。我们无法更改字符串...
阅读 3 分钟
如何在 Java 中获取字符串输入 Java Line() 方法 Scanner 类的 Line() 方法用于从用户那里获取字符串。它定义在 java.util.Scanner 类中。Line() 方法读取文本直到行尾。读取该行后,...
阅读 2 分钟
在 Java 中,包是类、接口、枚举和注解的集合。Java 包含许多预定义包,如 java.lang、java.io、java.net 等。当我们创建任何 Java 程序时,java.lang 包都会被默认导入。我们不需要写包名...
阅读 3 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India