【算法】一维、二维前缀和 解决算法题(C++)

文章目录

  • 1. 前缀和算法 介绍
  • 2. 一维前缀和 模板引入
    • DP34【模板】前缀和
  • 3. 利用一维前缀和 解题
    • 724.寻找数组的中心下标
    • 238.除自身以外数组的乘积
    • 560.和为K的子数组
    • 974.和可被K整除的子数组
    • 525.连续数组
  • 二维前缀和 模板
    • 1314.矩阵区域和

1. 前缀和算法 介绍

前缀和算法 用于高效地计算 数组或序列 中某个区间内元素的和。

前缀和数组是一个辅助数组,其每个元素存储原始数组从开头到当前位置的元素和。通过提前计算前缀和数组,可以在O(1)的时间复杂度内快速计算出任意区间内的元素和。

2. 一维前缀和 模板引入

DP34【模板】前缀和

在这里插入图片描述

这道题目帮助我们 理解前缀和模板使用前缀和数组

思路

  • 题意分析:题目要求我们返回 数组中l~r范围内所有元素的和

  • 我们引出前缀和数组dp的使用:
    在这里插入图片描述

  • 解法:前缀和数组

    1. 我们首先通过循环dp[i] = dp[i-1] + arr[i] 进行dp数组的初始化(预处理)
    2. 再根据找到的规律,l~r的范围和即为dp[r]-dp[l-1]

代码

int main() {int n = 0, q = 0;cin >> n >> q;vector<int> arr(n+1); // 下标从1开始,数组大小为n+1// 写入数组for(int i = 1; i <= n; ++i) cin >> arr[i];// 预处理前缀和数组vector<long long> dp(n+1); // long long 防止溢出for(int i = 1; i <= n; ++i) dp[i] = dp[i-1] + arr[i];// 使用前缀和数组while(q--){int l, r;cin >> l >> r;cout << dp[r] - dp[l-1] << endl;}return 0;
}

3. 利用一维前缀和 解题

724.寻找数组的中心下标

在这里插入图片描述

思路

在这里插入图片描述

  • 题意分析:要求我们找到数组的中心下标,中心下标满足:左侧元素和==右侧元素和
  • 解法:前缀和数组 + 后缀和数组
    1. 预处理前缀和 / 后缀和数组
      • p[i] = p[i-1] + nums[i-1];
      • s[i] = s[i+1] + nums[i+1];
    2. 遍历数组:找到满足条件的中心下标(p[i] == s[i])
    3. 细节注意:关于创建两数组时,循环条件从哪到哪。

代码

int pivotIndex(vector<int>& nums) {int n = nums.size();// 预处理前缀和数组vector<int> p(n); // P[i]:[0, i-1] 之间所有元素之和; for(int i = 1; i < n; ++i) // p[0] == 0 s[n-1] == 0]p[i] = p[i-1] + nums[i-1];// 预处理后缀和数组vector<int> s(n); // s[i]:[i+1, n-1] 之间所有元素之和for(int i = n - 2; i >= 0; i--)s[i] = s[i+1] + nums[i+1];// 通过前缀和/后缀和数组找到中心下标int i;for(i = 0; i <= n - 1; ++i){if(p[i] == s[i])return i;}return -1;
}

238.除自身以外数组的乘积

在这里插入图片描述

思路

  • 题意分析:返回数组answer,answer[i]为nums中除去自身的其余元素乘积。
  • 解法:前缀积数组 + 后缀积数组
    1. 我们知道:不论是前缀和还是前缀积数组,p[i]的值代表0~i-1位置的和/积,不包括其自身
    2. 则当我们求出数组的前缀积和后缀积后,answer[i] 即为 p[i] * s[i]。

在这里插入图片描述

代码

vector<int> productExceptSelf(vector<int>& nums) {int n = nums.size();vector<int> p(n), s(n);p[0] = s[n-1] = 1; // 边界条件// 构建前缀积数组for(int i = 1; i <= n - 1; ++i)p[i] = p[i-1] * nums[i-1];// 构建后缀积数组for(int i = n-2; i >= 0; --i)s[i] = s[i+1] * nums[i+1];vector<int> answer(n);for(int i = 0; i < n; ++i)answer[i] = p[i] * s[i];return answer;
}

560.和为K的子数组

思路

  • 题意分析:题目要求找到和为k的子数组的个数
  • 解法一:暴力枚举
    1. 一道题如果没有思路,首先可以想暴力解法
    2. 即:用两个循环遍历所有子数组,找到和为k的
    3. 缺点:时间开销大,时间复杂度O(n^2)
  • 为什么不能使用双指针(滑动窗口)?
    • 我们知道,双指针适合解决子数组问题,但其是解决连续子数组,这道题满足要求的子数组不一定连续。且数组中存在负数,也不能利用单调性使用滑动窗口。
  • 解法二:前缀和 + 哈希表
    在这里插入图片描述
    • 如上图所示

代码

int subarraySum(vector<int>& nums, int k) {int sum = 0, count = 0; // sum存储前缀和unordered_map<int, int> hash;hash[0] = 1; // 特殊情况:当子数组的第一个元素就满足条件的情况时for(int x : nums){sum += x;// 以x为结尾的子数组,值为sum-k,则存在满足和为k的子数组if(hash.count(sum-k)) count += hash[sum-k];hash[sum]++;}return count;
}

974.和可被K整除的子数组

在这里插入图片描述

思路

  • 题意分析:此题和前一题很像,只是从求和为k的子数组变成求和可被k整除的子数组的个数
  • 解法:前缀和 + 哈希表
    1. 思路与之前一致,我们每次在更新前缀和sum后,更新余数r,如果哈希表中存在则更新结果
  • 细节注意:同理为了防止前缀和为0的子数组满足条件,则将hash[0%k](就是0)定为1

代码

int subarraysDivByK(vector<int>& nums, int k) {// C++,java 中负数%正数=负数// 为了使余数满足题目条件,余数计算为(sum % k + k) % kint sum = 0, count = 0;unordered_map<int, int> hash;hash[0 % k] = 1; // hash[0] = 1;for(int x : nums){sum += x;int r = (sum % k + k) % k;if(hash.count(r)) count += hash[r];hash[r]++;}return count;
}

525.连续数组

在这里插入图片描述

思路

  • 题意分析:要求找到有相同数量0和1的最长子数组
  • 这道题要求我们找到最长连续子数组,但是没有直接单调性,不能使用滑动窗口解题
  • 将数组中的1全部改为0,题目就转化为了:找和为0的连续最长子数组
    • 相当于将和为K的子数组改为了和为0的子数组 ,但需要注意的是,这道题要求的是最长子数组的长度:所以我们用哈希表分别存储前缀和+下标
  • 解法:前缀和 + 哈希表
    • 我们每次将前缀和加入到数组中,如果已经存在,则根据长度更新结果
    • 否则将当前下标与前缀和加入到hash中
  • 细节注意:因为我们计算长度是用:下标i-hash[sum]
    • 如果首位就是满足条件的,此时长度应为1
    • 即i - hash[0] = 1,此时i为0,为了保证特殊情况,我们将hash[0]设为-1

在这里插入图片描述

代码

int findMaxLength(vector<int>& nums) {int sum = 0, ret = 0;// 将数组中的0改为-1,题目可以演化为:求和为0的子数组//for(int &x : nums)  x = 0 ? -1 : x;unordered_map<int, int> hash; // 哈希表存放前缀和以及下标hash[0] = -1;for(int i = 0; i < nums.size(); ++i){sum += nums[i] == 0 ? -1 : 1; // 更新前缀和if(hash.count(sum)) // 前缀和sum存在 则更新ret(hash[sum] 为前缀和尾部下标, i-hash[sum] 为 连续数组长度)ret = max(ret, i - hash[sum]);elsehash[sum] = i;}return ret;
}

二维前缀和 模板

1314.矩阵区域和

在这里插入图片描述

思路

  • 题意分析:题目要求返回answer矩阵,矩阵每一位元素可以理解为是以mat的每一位为中心,向上下左右分别扩展k个单位的元素总和。

  • 解法:二维前缀和
    在这里插入图片描述

    在这里插入图片描述

    1. 根据上面的图,我们首先用两层循环预处理前缀和矩阵
    2. 随后使用前缀和矩阵:只需要根据当前的(i, j)下标找到其向四周扩散的矩阵的左上和右下的坐标即可
    3. 根据求得的(x1, y1) (x2, y2) 以及我们算出的公式计算结果
  • 需要注意的是,最好不要死记模板公式,理解了过程,做题的时候可以模拟,自然会想出来过程

代码

vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {int m = mat.size(), n = mat[0].size();// 预处理前缀和矩阵vector<vector<int>> dp(m+1, vector<int>(n+1)); // 扩充一行一列:对应下标for(int i = 1; i <= m; ++i)for(int j = 1; j <= n; ++j)dp[i][j] = dp[i-1][j] + dp[i][j-1] + mat[i-1][j-1] - dp[i-1][j-1];// 使用前缀和矩阵 构建answervector<vector<int>> answer(m, vector<int>(n));for(int i = 0; i < m; ++i){for(int j = 0; j < n; ++j){// answer[0][0] 对应 dp[1][1],把坐标+1int x1 = max(i-k, 0) + 1, y1= max(j-k, 0) + 1;int x2 = min(i+k, m-1) + 1, y2 = min(j+k, n-1) + 1;answer[i][j] = dp[x2][y2] - dp[x2][y1-1] - dp[x1-1][y2] + dp[x1-1][y1-1];}}return answer;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/316557.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

opencv期末练习题(2)附带解析

图像插值与缩放 %matplotlib inline import cv2 import matplotlib.pyplot as plt def imshow(img,grayFalse,bgr_modeFalse):if gray:img cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)plt.imshow(img,cmap"gray")else:if not bgr_mode:img cv2.cvtColor(img,cv2.COLOR_B…

图像识别快速实现

文本的跑通了&#xff0c;接下来玩玩图片场景 1. 引入模型 再另起类test_qdrant_img.py&#xff0c;转化图片用到的模型和文本不太一样&#xff0c;我们这里使用ResNet-50模型 import unittest from qdrant_client.http.models import Distance, VectorParams from qdrant_cl…

一起读《奔跑吧Linux内核(第2版)卷1:基础架构》- 大小端字节序

关注 点赞 不错过精彩内容 大家好&#xff0c;我是硬核王同学&#xff0c;最近在做免费的嵌入式知识分享&#xff0c;帮助对嵌入式感兴趣的同学学习嵌入式、做项目、找工作! Hello&#xff0c;大家好我是硬核王同学&#xff0c;是一名刚刚工作一年多的Linux工程师&#xff0…

【FPGA/verilog -入门学习15】vivado FPGA 数码管显示

1&#xff0c;需求&#xff1a;使用xc720 开发板的8个数码管显示12345678 2&#xff0c;需求分析&#xff1a; 75hc595 1&#xff0c;74hc595驱动&#xff0c;将串行数据转换成并行输出。对应研究手册 2&#xff0c;发送之前将要发的数据&#xff0c;合并成高8位:SEG,低8位&…

我在CSDN的2023年

一、引言 在2023年的这一年当中&#xff0c;在CSDN的生活让我得到许多知识与启发&#xff0c;也让我获得一些快乐和成就 二、自己的收获 在这一年当中&#xff0c;我从一个只会看别人写的文章解决问题到&#xff0c;可以自己写文章帮别人解决问题&#xff0c;这种成就感是极大…

内衣迷你洗衣机什么牌子好?四款最好用的迷你洗衣机品牌

最近这两年在洗衣机中火出圈的内衣洗衣机&#xff0c;它不仅可以清洁我们较难清洗的衣物&#xff0c;自带除菌功能&#xff0c;可以让衣物上的细菌&#xff0c;还能在清洗的过程中呵护我们衣物的面料&#xff0c;虽然说它是内衣洗衣机&#xff0c;它的功能不止可以清洗内衣&…

(NeRF学习)NeRFStudio安装win11

参考&#xff1a; 【深度学习】【三维重建】windows11环境配置tiny-cuda-nn详细教程nerfstudio介绍及在windows上的配置、使用NeRFStudio官网githubRuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory原因及解决 目录 requireme…

Linux使用yum命令安装postgrepsql

1.检查安装源 yum search postgresql 2.安装 yum install postgresql-server 3.启动数据库 service postgresql start 4.查看启动状态 service postgresql status 5.登陆测试 su - postgrep psql \l6.远程连接 6.1修改配置文件 在pg_hba.conf增加host all all 0.0.0…

地产集团如何利用数据做好经营分析?

企业数字化转型离不开数据的支持&#xff0c;如何通过数据的沉淀、拉通及分析&#xff0c;更好的赋能业务和管理实现价值创造&#xff0c;是当前地产数字化面临的首要问题。 一、地产集团数据处理和应用的现状 目前地产集团都是多业态的发展模式&#xff0c;包括地产住宅开发、…

python入门

目录 1.数据的输入和输出 1.输入 ​编辑 2.输出 2.if语句&#xff0c;条件判断 3.循环 1.while 2.for 1.数据的输入和输出 python不用像c语言一样给一个变量初始化一个类型&#xff0c;直接赋值就行了 像这样&#xff0c;连分号都不用加 这里我用python自带的 type函数…

How to understand the Pangu model in Huawei Cloud

How to understand the Pangu model in Huawei Cloud 参考文献 产品首页 / 盘古大模型文档首页 / 盘古大模型

Modbus 通信协议 二

Modbus 常用缩写 通用Modbus帧结构 -应用数据单元&#xff08;ADU&#xff09; Modbus数据模型 Modbus ADU 和 PDU 的长度 Modbus PDU结构 串行链路上的 Modbus 帧结构 Modbus 地址规则 ASCLL 模式 和 RTU 模式的比较 RTU 模式 RTU 模式位序列 帧格式 帧的标识与鉴别 CRC 循环冗…