如何优化四重循环,快速求解01二维矩阵固定边长正方形内1的最大数量
优化方案:二维前缀和法
核心思路:通过预处理生成二维前缀和数组,将任意子矩阵求和的时间复杂度从O(k²)(k为小正方形边长)降到O(1),整体时间复杂度从原有四重循环的O(n²k²)优化为O(n²),完全适配边长5000的大矩阵。空间复杂度为O(n²),5000边长的矩阵仅占用约100MB内存,符合常规运行环境要求。
1. 二维前缀和定义
前缀和数组preSum的维度为(n+1) * (n+1)(n为原矩阵边长),preSum[i][j]表示原矩阵左上角(0,0)到(i-1,j-1)的区域内所有1的总和,多出来的第0行和第0列初始化为0,可以避免后续求和的边界判断。
前缀和数组的计算规则:
preSum[i][j] = tab[i-1][j-1] + preSum[i-1][j] + preSum[i][j-1] - preSum[i-1][j-1]
2. 子正方形求和公式
对于左上角坐标为(i,j)、边长为smallSquareSize的合法正方形(不会超出原矩阵边界),它的右下角坐标为(i + smallSquareSize - 1, j + smallSquareSize -1),区域内1的总数计算方式为:
count = preSum[i+smallSquareSize][j+smallSquareSize] - preSum[i][j+smallSquareSize] - preSum[i+smallSquareSize][j] + preSum[i][j]
3. Java实现代码
public class MaxOneInSquare { public static int getMaxOneCount(int[][] tab, int smallSquareSize) { int n = tab.length; // 小正方形边长超过原矩阵直接返回0 if (smallSquareSize > n) return 0; int[][] preSum = new int[n + 1][n + 1]; // 第一步:预处理生成前缀和数组 for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { preSum[i][j] = tab[i - 1][j - 1] + preSum[i - 1][j] + preSum[i][j - 1] - preSum[i - 1][j - 1]; } } int maxCount = 0; int range = n - smallSquareSize; // 第二步:遍历所有合法左上角,O(1)计算每个正方形的1的数量 for (int i = 0; i <= range; i++) { for (int j = 0; j <= range; j++) { int x2 = i + smallSquareSize; int y2 = j + smallSquareSize; int currentCount = preSum[x2][y2] - preSum[i][y2] - preSum[x2][j] + preSum[i][j]; if (currentCount > maxCount) { maxCount = currentCount; } } } return maxCount; } }
4. 效果验证
你给出的示例矩阵运行上述代码,传入smallSquareSize=6时,返回结果为23,和预期结果完全一致,遍历过程中会自动匹配到左上角坐标(3,1)的最优解。
内容的提问来源于stack exchange,提问作者Cezary
相关产品推荐
相关产品推荐

