问题:
有一个任意的二维数组, 现要求写一个方法, 传入四个int类型的参数(row1, col1, row2, row2), 由这四个参数构成一个子二维数组, row1和col1是子二维数组的左上角元素的索引, row2和row2是子二维数组的右下角元素的索引. 现要求对这个子二维数组的元素求和.
简单理解的方法:
直接将范围内的值进行相加
图示:
代码演示:
public int sum(int row1, int col1, int row2, int col2) {
int sum = 0;
int length = nums.length;
for (int i = row1; i <= row2; i++) {
for (int j = col1; j <= col2; j++) {
sum += nums[i][j];
}
}
return sum;
}
这个方法简单易理解, 但是有很多弊端, 如:当row2与row1差值很大, col2与col1差值很大, 程序循环的次数大大增加; 或是当这个方法被调用很多次的时候, 每一次都需要进行循环计算. 是的程序的执行效率大大降低
改进方法:
怎么解决这一问题呢, 我们可以提前计算好每一块区间的和将其存在一个二维数组中, 当调用sum()方法的时候, 只需要进行一些简单的加减计算即可得到结果,
先计算二维和数组:
计算方法图示:
图示:
代码演示:
public class Demo {
static int[][] nums;
public static void main(String[] args) {
nums = new int[][]{
{47, 21, 33, 57, 35},
{68, 1, 17, 92, 78},
{43, 91, 59, 86, 74},
{1, 74, 48, 59, 2},
{7, 56, 40, 63, 21},
{65, 63, 18, 98, 75}};
// 创建二维和数组的对象, 里面封装了二维数组指定区间求和的方法
NumMatrix numMatrix = new NumMatrix(nums);
// 打印原数组
System.out.println("原数组");
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < nums[0].length; j++) {
System.out.printf("%-3d", nums[i][j]);
}
System.out.println();
}
numMatrix.show();// 打印二维和数组
// 一定区间求和
System.out.println("结果 = " + numMatrix.sumRegion(2, 1, 4, 2));
}
static class NumMatrix {
int[][] sumMatrix;
// 通过二维数组计算和二维数组
public NumMatrix(int[][] matrix) {
int row = matrix.length;
int col = matrix[0].length;
// 创建一个大小为原数组+1的二维数组, 目的是为了留出一行一列做辅助行列, 为方便计算
sumMatrix = new int[row + 1][col + 1];
// sumMatrix[i][0], sumMatrix[0][i]不进行使用只当作辅助空间
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
// 求和方式: 上和 + 左和 + - 左上和(重复计算的部分) + 当前位置值
sumMatrix[i + 1][j + 1] = sumMatrix[i][j + 1] + sumMatrix[i + 1][j] - sumMatrix[i][j] + matrix[i][j];
}
}
}
// 打印二维和数组
public void show(){
System.out.println("二维和数组");
for (int i = 1; i < sumMatrix.length; i++) {
for (int j = 1; j < sumMatrix[0].length; j++) {
System.out.printf("%-5d", sumMatrix[i][j]);
}
System.out.println();
}
}
public int sumRegion(int row1, int col1, int row2, int col2) {
int row = sumMatrix.length - 1;
int col = sumMatrix[0].length - 1;
// 条件判断, 如果输入不合法返回 -1
if (!(row1 >= 0 && col1 >= 0 && row2 < row && col2 < col)
|| row1 > row2 || col1 > col2) {
return -1;
}
// 区间求和:大区间 - 两块小区间 + 被重复减去区间
return sumMatrix[row2 + 1][col2 + 1] - sumMatrix[row2 + 1][col1] - sumMatrix[row1][col2 + 1] + sumMatrix[row1][col1];
}
}
}