剑指 Offer II 013. 二维子矩阵的和

本文详细介绍了如何使用二维前缀和算法快速计算二维矩阵中任意子矩阵元素的总和,包括一维前缀和的两种方向计算方法,并进一步拓展到二维前缀和的计算逻辑与实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定一个二维矩阵 matrix,以下类型的多个请求:
计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2)

掌握一维前缀和和二维前缀和
进而能掌握一维前缀积和二维前缀积

class NumMatrix {
private:
	vector<vector<int>> sums; // 一维前缀和
public:
	// 行的一维前缀
    NumMatrix(vector<vector<int>>& matrix) {
        //在初始化的时候搞一些必要操作
		int row = matrix.size();
		int col = matrix[0].size();
		if(row>0 && col>0) {
			// resize完之后,可用size重新获取更新后的大小,同时内存被初始化为0
			// sums[i][j]的意思是第i行(i从0开始),前j列元素的总和(j从1开始)
			sums.resize(row, vector<int>(col + 1, 0));
			for(int i = 0; i < row; i++) {
				for(int j = 1; j <= col; j++) {
					sums[i][j] = sums[i][j - 1] + matrix[i][j - 1];
				}
			}
		}
		
    }

    int sumRegion(int row1, int col1, int row2, int col2) {
		int sum = 0;
		// sums[0][1]是第0行,前1列的和
		// sums[0][2]是第0行,前2列的和
		
		// 行固定好之后,计算列值差
		for(int i = row1; i <= row2; i++) {
			// 前 col2+1 列的和 减去 前 col1 列的和
			// 比如 col1 = 2, col2 = 4
			// 则需要计算 0+1+2+3+4列的和 减去 0+1列的和
			// 所以就是 前col2+1 列的和减去 前 col1 列的和
			sum += (sums[i][col2 + 1] - sums[i][col1]);
		}
		return sum;
    }
};
class NumMatrix {
private:
	vector<vector<int>> sums; // 一维前缀和
public:
	// 列的一维前缀
    NumMatrix(vector<vector<int>>& matrix) {
        //在初始化的时候搞一些必要操作
		int row = matrix.size();
		int col = matrix[0].size();
		if(row>0 && col>0) {
			// resize完之后,可用size重新获取更新后的大小,同时内存被初始化为0
			// sums[i][j]的意思是第j列(j从0开始),前i行元素的总和(i从1开始)
			sums.resize(row + 1, vector<int>(col, 0));
			for(int j = 0; j < col; j++) {
				for(int i = 1; i <= row; i++) {
					sums[i][j] = sums[i - 1][j] + matrix[i - 1][j];
				}
			}
		}
		
    }

    int sumRegion(int row1, int col1, int row2, int col2) {
		int sum = 0;
		// sums[1][0]是第0列,前1行的和
		// sums[3][0]是第0行,前3行的和
		
		// 列固定好之后,计算行值差
		for(int j = col1; j <= col2; j++) {
			// 前 row2+1 行的和 减去 前 row1 行的和
			// 比如 row1 = 2, row2 = 4
			// 则需要计算 0+1+2+3+4行的和 减去 0+1行的和
			// 所以就是 前row2+1 行的和减去 前 row1 行的和
			sum += (sums[row2+1][j] - sums[row1][j]);
		}
		return sum;
    }
};

【二维前缀和】

class NumMatrix {
private:
	vector<vector<int>> sums; // 二维前缀和
public:
    NumMatrix(vector<vector<int>>& matrix) {
        //在初始化的时候搞一些必要操作
		int row = matrix.size();
		int col = matrix[0].size();
		if(row>0 && col>0) {
			// resize完之后,可用size重新获取更新后的大小,同时内存被初始化为0
			// sums[i][j]的意思是前i行(i从1开始),前j列元素的总和(j从1开始)
			sums.resize(row + 1, vector<int>(col + 1, 0));
			for(int i = 1; i <= row; i++) {
				for(int j = 1; j <= col; j++) {
					sums[i][j] = sums[i - 1][j] + sums[i][j - 1] + matrix[i - 1][j - 1] - sums[i - 1][j - 1];
				}
			}
		}
		
    }

    int sumRegion(int row1, int col1, int row2, int col2) {
		return sums[row2+1][col2+1] + sums[row1][col1] - sums[row2+1][col1] - sums[row1][col2+1];
    }
};

eg
对于数组matrix:
4 5 7
2 1 3
9 8 6

计算之后的sums就是
0 0 0 0
0 4 9 16
0 6 12 22
0 15 29 45

前i行前j列的值 = 前i-1行前j-1列的值+第i-1行前j-1列的值+第j-1列前i-1行的值+matrix[i-1][j-1]的值
前3行前3列的值 = 前2行前2列的值+第2行前2列的值+第2列前2行的值+matrix[2][2]的值

第2行指的是从0开始的行,第2列指的是从0开始的列

如何计算 第i-1行前j-1列的值 ?
第i-1行前j-1列的值 = 前i行前j-1列的值 - 前i-1行前j-1列的值
第2行前2列的值 = 前3行前2列的值 - 前2行前2列的值 = 第2行前2列的值

如何计算 第j-1列前i-1行的值 ?
第j-1列前i-1行的值 = 前i-1行前j列的值 - 前i-1行前j-1列的值
第2列前2行的值 = 前2行前3列的值 - 前2行前2列的值 = 前2行第2列的值

sums[i][j] = sums[i - 1][j] + sums[i][j - 1] + matrix[i - 1][j - 1] - sums[i - 1][j - 1];

那么 第row1行第col1列 到 第row2行第col2列之间的和 =
前row2+1行前col2+1列的值 - 前row1行前col1列的值 - (第row1行~第row2行)前col1列的值 - 前row1行(第col1列~第col2列)
进而可以表示为:
(第row1行~第row2行)前col1列的值 = 前row2+1行前col1列的值 - 前row1行前col1列的值
前row1行(第col1列~第col2列)的值 = 前row1行前col2+1列的值 - 前row1行前col1列的值

sums[row2+1][col2+1] + sums[row1][col1] - sums[row2+1][col1] - sums[row1][col2+1]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值