算法复盘——前缀和

一、思路

前缀和 :预处理数组,快速计算区间和,O(n)预处理→O(1)查询。

二、例题

一维前缀和

1.区域和检索 - 数组不可变

303. 区域和检索 - 数组不可变 - 力扣(LeetCode)

代码实现:
cpp 复制代码
class NumArray {
    private:
        vector <int> pre_sum;
    public:
        NumArray(vector<int>& nums) {
            int n = nums.size();
            pre_sum.resize(n+1, 0);
            for(int i = 0; i < n; i++)  pre_sum[i+1] = pre_sum[i] + nums[i];
        }
        
        int sumRange(int left, int right) {
            return pre_sum[right + 1] -pre_sum[left];
        }
};

2.最大子段和

P1115 最大子段和 - 洛谷

代码实现:
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int  N = 2e5 + 10;
int a[N], n, premin, ret; 
int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++)
	{
		int x; cin >> x;
		a[i] = a[i-1] + x;
	}
	int ret = 0xc0c0c0c0;
	for(int i = 1; i <= n; i++)
	{
		ret = max(ret, a[i] - premin);
		premin = min(premin, a[i]);
	}
	cout << ret << endl;
	return 0;
}

3.和为 K 的子数组

560. 和为 K 的子数组 - 力扣(LeetCode)

思路:

先计算前缀和数组,然后在遍历过程中维护前面出现过的最小前缀和。对于每个位置,用当前前缀和减去最小前缀和,就能得到以当前位置结尾的最大子数组和。

代码实现:
cpp 复制代码
class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> mp;
        mp[0] = 1; // 前缀和为0的情况出现1次(对应pre_sum[0])
        int pre_sum = 0, cnt = 0;
        for(int num : nums) {
            pre_sum += num;
            // 查找之前有多少个前缀和等于 pre_sum - k
            if(mp.contains(pre_sum - k) )  cnt += mp[pre_sum - k];
            mp[pre_sum]++;
        }
        return cnt;
    }
};

二位前缀和

1.激光炸弹

P2280 [HNOI2003] 激光炸弹 - 洛谷

问题分析:
  • 地图坐标范围:0 ≤ x,y ≤ 5000
  • 同一位置可能有多个目标,价值要累加
  • 炸弹是 R×R 正方形 ,目标必须在正方形内部才被摧毁
  • 目标:找一个 R×R 正方形,使内部总价值最大
思路:

先把所有点的价值累加进矩阵,再算前缀和。然后枚举每个 R×R 正方形的右下角,用前缀和公式 O (1) 算和,最后取最大。

代码实现:
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 5010; 
int n, m;
LL a[N][N], st[N][N];
int main()
{
	cin >> n >> m;
	while(n--)
	{
		int x, y, v; cin >> x >> y >> v;
		a[++x][++y] += v;
	}
	n = 5001;
	// 前缀和数组
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= n; j++)
		{
			st[i][j] = st[i-1][j] + st[i][j-1] - st[i-1][j-1] + a[i][j];
		}
	 } 
	 // 枚举炸弹的位置
	 LL ret = 0;
	 m = min(m, n);
	 for (int x2 = m; x2 <= n; x2++)
	 {
	 	for (int y2 = m; y2 <= n; y2++)
	 	{
	 		int x1 = x2 - m + 1, y1 = y2 - m + 1;
	 		LL tmp = st[x2][y2] - st[x1-1][y2] - st[x2][y1-1] + st[x1-1][y1-1]; 
	 		ret = max(ret, tmp);
		 }
	  } 
	  cout << ret << endl;
	return 0;
 } 
相关推荐
handler0118 小时前
从源码到二进制:深度拆解 Linux 下 C 程序的编译与链接全流程
linux·c语言·开发语言·c++·笔记·学习
电子云与长程纠缠18 小时前
UE5 两种方式解决Decal Actor贴花拉伸问题
学习·ue5·游戏引擎
red_redemption18 小时前
自由学习记录(172)
学习·cache line 64b·重用距离
阿荻在肝了19 小时前
Agent学习六:LangGraph学习-持久化与记忆一
python·学习·agent
6Hzlia20 小时前
【Hot 100 刷题计划】 LeetCode 739. 每日温度 | C++ 逆序单调栈
c++·算法·leetcode
良木生香20 小时前
【C++初阶】:STL——String从入门到应用完全指南(1)
c语言·开发语言·数据结构·c++·算法
XWalnut20 小时前
LeetCode刷题 day16
数据结构·算法·leetcode·链表·动态规划
寒秋花开曾相惜21 小时前
(学习笔记)4.1 Y86-64指令集体系结构(4.1.4 Y86-64异常&4.1.5 Y86-64程序)
开发语言·jvm·数据结构·笔记·学习
莹宝思密达21 小时前
【AI学习】 playwright-cli + SKILL 替换 chrom-devTools-MCP
学习