【leetcode】前缀和

内容摘抄自: 小而美的算法技巧:前缀和数组 | labuladong 的算法小抄

一维数组的前缀和

看这个 preSum 数组,若想求索引区间 [1, 4] 内的所有元素之和,

就可以通过 preSum[5] - preSum[1] 得出。

cpp 复制代码
class NumArray {
    private:
        // 前缀和数组
        vector<int> preSum;
    
    public:
        /* 输入一个数组,构造前缀和 */
        NumArray(vector<int>& nums) {
            // preSum[0] = 0,便于计算累加和
            preSum.resize(nums.size() + 1);
            // 计算 nums 的累加和
            for (int i = 1; i < preSum.size(); i++) {
                preSum[i] = preSum[i - 1] + nums[i - 1];
            }
        }
        
        /* 查询闭区间 [left, right] 的累加和 */
        int sumRange(int left, int right) {
            return preSum[right + 1] - preSum[left];
        }
};

二维数组的前缀和

如leetcode 304:

注意任意子矩阵的元素和可以转化成它周边几个大矩阵的元素和的运算:

而这四个大矩阵有一个共同的特点,就是左上角都是 (0, 0) 原点。

那么做这道题更好的思路和一维数组中的前缀和是非常类似的,我们可以维护一个二维 preSum 数组,专门记录以原点为顶点的矩阵的元素之和,就可以用几次加减运算算出任何一个子矩阵的元素和:

值得注意的是 preSum数组要比matrix数组半圈,大出来的这半圈默认为值为0。

同时 再求preSum的时候 要捋清楚和matrix 索引的对应关系

cpp 复制代码
class NumMatrix {
private:
    // 定义:preSum[i][j] 记录 matrix 中子矩阵 [0, 0, i-1, j-1] 的元素和
    vector<vector<int>> preSum;
    
public:
    NumMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        if (m == 0 || n == 0) return;
        // 构造前缀和矩阵
        preSum = vector<vector<int>>(m + 1, vector<int>(n + 1));
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // 计算每个矩阵 [0, 0, i, j] 的元素和
                preSum[i][j] = preSum[i-1][j] + preSum[i][j-1] + matrix[i - 1][j - 1] - preSum[i-1][j-1];
            }
        }
    }
    
    // 计算子矩阵 [x1, y1, x2, y2] 的元素和
    int sumRegion(int x1, int y1, int x2, int y2) {
        // 目标矩阵之和由四个相邻矩阵运算获得
        return preSum[x2+1][y2+1] - preSum[x1][y2+1] - preSum[x2+1][y1] + preSum[x1][y1];
    }
};

笔试真题:蛋糕切割问题(切蛋糕问题)

美团0812秋招笔试真题解析

cpp 复制代码
#include <cstdint>
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
 
class Solution
{
public:
	Solution(vector<vector<int>>& a)
	{
		int n = a.size(); //行
		int m = a[0].size();   //列
		if (!n && !m) return;
		//构造前缀和数组
		preSum = vector<vector<long>>(n + 1, vector<long>(m + 1, 0));
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				//计算每一个矩阵[0,0,i,j]的元素和
				preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + a[i-1][j-1] - preSum[i - 1][j - 1];
 
	}
 
	long sumRegion(int x1, int y1, int x2, int y2)
	{
		return preSum[x2+1][y2+1] - preSum[x1][y2+1] - preSum[x2+1][y1] + preSum[x1][y1];
	}
 
	int getMin(vector<vector<int>>& a)
	{
		int n = a.size();
		int m = a[0].size();
		int res = INT_MAX;
 
		for (int i = 0; i < m; i++)
		{
			//0,0,n-1,i     0,i+1,n-1,m-1
			long sum1 = sumRegion(0, 0, n - 1, i);
			long sum2 = sumRegion(0, i+1, n - 1, m - 1);
			res = res < abs(sum1-sum2)? res:abs(sum1-sum2);
		}

		for (int j = 0; j < n; j++)
		{
			//0,0,j,m-1     j+1,0,n-1,m-1
			long sum1 = sumRegion(0, 0,  j, m-1);
			long sum2 = sumRegion(j+1, 0, n -1, m - 1);
			res = res < abs(sum1-sum2)? res:abs(sum1-sum2);
		}
	    
		return res;
	}
 
 
private:
 
	//preSum[i][j]用于记录a中子矩阵的元素和
	vector<vector<long>> preSum;
 
};
 
 
 
int main()
{
	int n, m;
	cin >> n >> m;
	vector<vector<int>> a(n, vector<int>(m, 0));
 
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
		{
			cin >> a[i][j];
		}
	Solution MySolution(a);
	cout<< MySolution.getMin(a) << endl;

}
相关推荐
码破苍穹ovo3 小时前
堆----1.数组中的第K个最大元素
java·数据结构·算法·排序算法
愤怒的小鸟~~~3 小时前
c语言创建的一个队列结构(含有这个头指针和这个尾指针的结构具有一定的参考价值)
c语言·开发语言·算法
Joker-01115 小时前
深入 Go 底层原理(十二):map 的实现与哈希冲突
算法·go·哈希算法·map
金融小师妹6 小时前
AI量化模型解析黄金3300关口博弈:市场聚焦“非农数据”的GRU-RNN混合架构推演
大数据·人工智能·算法
金融小师妹6 小时前
基于LSTM-GRU混合网络的动态解析:美联储维稳政策与黄金单日跌1.5%的非线性关联
大数据·人工智能·算法
白日梦想家-K6 小时前
题单【模拟与高精度】
开发语言·c++·算法
岁忧7 小时前
(LeetCode 面试经典 150 题) 138. 随机链表的复制 (哈希表)
java·c++·leetcode·链表·面试·go
重生之我是Java开发战士7 小时前
【C语言】内存函数与数据在内存中的存储
c语言·开发语言·算法
roman_日积跬步-终至千里8 小时前
【机器学习】“回归“算法模型的三个评估指标:MAE(衡量预测准确性)、MSE(放大大误差)、R²(说明模型解释能力)
算法·机器学习·回归
只会蓝桥杯能算acmer吗8 小时前
面试小总结
面试·职场和发展