刷题训练之前缀和

news2025/1/15 6:47:38

 > 作者:დ旧言~
> 座右铭:松树千年终是朽,槿花一日自为荣。

> 目标:熟练掌握前缀和算法。

> 毒鸡汤:学习,学习,再学习 ! 学,然后知不足。

> 专栏选自:刷题训练营

> 望小伙伴们点赞👍收藏✨加关注哟💕💕 

🌟前言分析

        最早博主续写了牛客网130道题,这块的刷题是让同学们快速进入C语言,而我们学习c++已经有一段时间了,知识储备已经足够了但缺少了实战,面对这块短板博主续写刷题训练,针对性学习,把相似的题目归类,系统的刷题,而我们刷题的官网可以参考:​​​​​​

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网

⭐知识讲解

前缀和只是一个算法的总称,其实前缀和可以分为前缀和,前缀积,这类算法更像是高中我们所学的数列的求和,寻找一组数列的规律,从而计算前缀和,这类题目很有规律的,学会画图,掌握题目的所隐藏的规律,这类题目就自然而然的可以解出。

⭐经典题型

🌙topic-->1

题目链接:1.前缀和

题目分析:

输入  n  个数字 ,求 q 次前缀和,这个 q 次前缀和范围在 l ~ r 之间 (不是数组的下标,而是数组第l 的数),输出多组数据。

算法原理:

  • 解法一:

暴力遍历数组,时间复杂度为O(n * q),这个解法会超时,所以我们不用这个算法。

  • 解法二:

采用前缀和的算法原理:

代码演示:

#include <iostream>
using namespace std;

const int N = 100001; // 数据大小
long long arr[N],dp[N];
int n,q; 

int main() 
{
    // 输入
    cin >> n >> q;
    // 存入数据
    for(int i = 1;i <= n;i++)
        cin >> arr[i];
    // 前缀和
    for(int i = 1;i <= n;i++)
        dp[i] = dp[i - 1] + arr[i];
    // 输出
    while(q--)
    {
        int l,r = 0;
        cin >> l >> r;
        // 计算前缀和
        cout << dp[r] - dp[l - 1] << endl;
    }
    return 0;
}

 🌙topic-->2

题目链接:2二维前缀和

题目分析:

在一个二维数组( n  *  m)中,求 q 次二维前缀和,其中需要输入两个二维坐标,求输入这个两个坐标矩阵的和。

算法原理:

  • 解法一:

暴力遍历二维数组,时间复杂度为O(n * m  * q),这个解法会超时,所以我们不用这个算法。

  • 解法二:

采用二维前缀和的算法原理:

代码演示:

#include <iostream>
using namespace std;

const int N = 1001; // 数据大小
int arr[N][N];
long long dp[N][N];
int n,m,q = 0;

int main() 
{
    // 输入
    cin >> n >> m >> q;
    // 读入数据
    for(int i = 1 ;i <= n;i++)
        for(int j = 1;j <= m;j++)
            cin >> arr[i][j];
    // 处理数据
    for(int i = 1;i <=n;i++)
        for(int j = 1;j <= m;j++)
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + arr[i][j] - dp[i - 1][j - 1];
    // 使用前缀和矩阵
    int x1,y1,x2,y2 = 0;
    while(q--)
    {
        cin >> x1 >> y1 >> x2 >> y2;
        // 采用公式
        cout << dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 -1][y1 - 1] << endl;
    }

    return 0;
}

 🌙topic-->3

题目链接:3.前缀和

题目分析:

数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。

如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。

算法原理:

  • 解法一:

暴力遍历一维数组,这个解法会超时,所以我们不用这个算法。

  • 解法二:

采用一维前缀和的算法原理:

代码演示:

class Solution {
public:
	int pivotIndex(vector<int>& nums) 
    {
		// lsum[i] 表⽰:[0, i - 1] 区间所有元素的和
		// rsum[i] 表⽰:[i + 1, n - 1] 区间所有元素的和
		int n = nums.size();
		vector<int> lsum(n), rsum(n);
		// 预处理前缀和后缀和数组
		for (int i = 1; i < n; i++)
			lsum[i] = lsum[i - 1] + nums[i - 1];
		for (int i = n - 2; i >= 0; i--)
			rsum[i] = rsum[i + 1] + nums[i + 1];
		// 判断
		for (int i = 0; i < n; i++)
			if (lsum[i] == rsum[i])
				return i;
		return -1;
	}
};

 🌙topic-->4

题目链接:4.前缀和

题目分析:

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

算法原理:

  • 解法一:

暴力遍历一维数组,这个解法会超时,所以我们不用这个算法。

  • 解法二:

采用一维前缀积的算法原理:

代码演示:

class Solution
{
public:
	vector<int> productExceptSelf(vector<int>& nums)
	{
		// lprod 表⽰:[0, i - 1] 区间内所有元素的乘积
		// rprod 表⽰:[i + 1, n - 1] 区间内所有元素的乘积
		int n = nums.size();
		vector<int> lprod(n + 1), rprod(n + 1);
		lprod[0] = 1, rprod[n - 1] = 1;
		// 预处理前缀积以及后缀积
		for (int i = 1; i < n; i++)
			lprod[i] = lprod[i - 1] * nums[i - 1];
		for (int i = n - 2; i >= 0; i--)
			rprod[i] = rprod[i + 1] * nums[i + 1];
		// 处理结果数组
		vector<int> ret(n);
		for (int i = 0; i < n; i++)
			ret[i] = lprod[i] * rprod[i];
		return ret;
	}
};

 🌙topic-->5

题目链接:5.前缀和

题目分析:

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。子数组是数组中元素的连续非空序列。

算法原理:

  • 解法一:

暴力遍历一维数组,定住一个元素向后寻找,时间复杂度为 O(n*n) ,这个解法会超时,所以我们不用这个算法。

  • 解法二:

采用一维前缀和的算法原理:

代码演示:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) 
    {
        unordered_map<int,int> hash;// 统计前缀和出现的个数
        hash[0] = 1;// 处理边界问题
        
        int sum = 0,ret = 0;
        // 循环
        for(auto x : nums)
        {
            sum = sum + x;// 累计起来
            if(hash.count(sum - k)) // 模拟指针向后移
                ret = ret + hash[sum - k];
            hash[sum]++;
        }
        return ret;
    }
};

🌙topic-->6

题目链接:6.前缀和

题目分析:

给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的(连续、非空) 子数组 的数目。

子数组 是数组的 连续 部分。

算法原理:

  • 解法一:

暴力遍历一维数组,定住一个元素向后寻找,时间复杂度为 O(n*n) ,这个解法会超时,所以我们不用这个算法。

  • 解法二:

采用一维前缀和的算法原理:

代码演示:

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k)
    {
        unordered_map<int, int> hash;
        hash[0 % k] = 1; // 0 这个数的余数
        int sum = 0, ret = 0;
        for (auto x : nums)
        {
            sum += x; // 算出当前位置的前缀和
            int r = (sum % k + k) % k; // 修正后的余数
            if (hash.count(r)) ret += hash[r]; // 统计结果
            hash[r]++;
        }
        return ret;
    }
};

🌙topic-->7

题目链接:7.前缀和

题目分析:

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

  • nums[i] 不是 0 就是 1

算法原理:

  • 解法一:

暴力遍历一维数组,定住一个元素向后寻找,时间复杂度为 O(n*n) ,这个解法会超时,所以我们不用这个算法。

  • 解法二:

采用一维前缀和的算法原理:

代码演示:

class Solution
{
public:
	int findMaxLength(vector<int>& nums)
	{
		unordered_map<int, int> hash;
		hash[0] = -1; // 默认有⼀个前缀和为 0 的情况
		int sum = 0, ret = 0;
		for (int i = 0; i < nums.size(); i++)
		{
			sum += nums[i] == 0 ? -1 : 1; // 计算当前位置的前缀和
			if (hash.count(sum)) ret = max(ret, i - hash[sum]);
			else hash[sum] = i;
		}
		return ret;
	}
};

🌙topic-->8

题目链接:8.前缀和

题目分析:

给你一个 m x n 的矩阵 mat 和一个整数 k ,请你返回一个矩阵 answer ,其中每个 answer[i][j] 是所有满足下述条件的元素 mat[r][c] 的和。

算法原理:

  • 解法一:

暴力遍历二维数组,定住一个元素向后寻找,时间复杂度为 O(n*n) ,这个解法会超时,所以我们不用这个算法。

  • 解法二:

采用二维前缀和的算法原理:(和第二题相似)

代码演示:

class Solution {
public:
	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));
		// 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] - dp[i - 1][j - 1] +
				mat[i - 1][j - 1];
		// 2. 使⽤
		vector<vector<int>> ret(m, vector<int>(n));
		for (int i = 0; i < m; i++)
			for (int j = 0; j < n; j++)
			{
				int x1 = max(0, i - k) + 1, y1 = max(0, j - k) + 1;
				int x2 = min(m - 1, i + k) + 1, y2 = min(n - 1, j + k) + 1;
				ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] +
					dp[x1 - 1][y1 - 1];
			}
		return ret;
	}
};

🌟结束语

       今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Oracle系统参数调整【数据库实例优化系列一】

Oracle实例是:内存组件和相关的后台进程组成。这些内存组件提高了数据库的运行,而后台进程负责管理系统和内存组件。 一、SGA和实例优化 Oracle的SGA是指的系统全局区。sga是数据库运行期间使用的一段公有内存,即数据库用户都可以访问这段内存,包括: 共享池、重做日志缓冲…

分享一些实用的工具

1、amCharts5&#xff1a;模拟航线飞行/业务分布图/k线/数据分析/地图等 网址&#xff1a; JavaScript mapping library: amCharts 5https://www.amcharts.com/javascript-maps/ Demo地址&#xff1a;Chart Demos - amChartshttps://www.amcharts.com/demos/#maps 他分为amC…

Xcode隐私协议适配

1. Privacy manifest files 1.1 简介 自己App或三方SDK&#xff08;通过XCFrameworks|Swift packages|Xcode projects集成的&#xff09;需要包含一个隐私清单文件&#xff08;privacy manifest&#xff09;叫作 PrivacyInfo.xcprivacy。它是一个属性列表&#xff0c;记录了A…

【Hadoop】-HDFS的存储原理[4]

目录 前言 一、fsck命令 1、HDFS副本块数量的配置 2、fsck命令查看文件的副本数 3、block配置 二、NameNode元数据 1、edits文件 2、fsigame文件 3、NameNode元数据管理维护 4、元数据合并控制参数 5、SecondaryNameNode的作用 三、HDFS数据的读写流程 1、数据写入…

2024第十五届蓝桥杯网络安全赛项WriteUp

欢迎关注公众号【Real返璞归真】回复【蓝桥杯2024】获取完整题目附件。 排名 安全知识 错1个选择题&#xff0c;题目说的不清楚&#xff0c;没搞懂题意。肯定不能用eval。错了理论题有点遗憾。 没想到这题前端是要解析json数据&#xff0c;排除CD选了A&#xff0c;结果发现正…

AI大模型日报#0427:阿里智能体“组装工厂”开源、Meta推70M参数SceneScript模型解码真实场景

导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。 标题: BattleAgent&#xff1a;再现历史事件&#xff0c;对历史战役进行多模态动态模拟&#xff5c;大模型论文摘要: 科技论文摘要&…

百度SDK创建应用地址解析失败问题

在百度SDK的设置里先用IP白名单校验全部都通过&#xff0c;项目上线之后再改就行 0.0.0.0/0

数据结构(七)---二叉树

目录 一.树的基本概念 二.树的性质 三.二叉树 1.二叉树的基本概念 2.特殊的二叉树 &#xff08;1&#xff09;满二叉树 &#xff08;2&#xff09;完全二叉树 &#xff08;3&#xff09;二叉排序树 &#xff08;4&#xff09;平衡二叉树 3.二叉树的性质 4.完全二叉树…

安装好fedora_kde系统后的操作

文章目录 1 前言2 办公软件2.1 输入法2.1.1 安装 fcitx52.1.2 安装 fcitx5-rime2.1.3 安装 東風破2.1.4 使用 東風破 安装 郭斌勇 大神的 新世纪五笔 项目2.1.5 配置 fcitx5-rime2.1.6 重新部署 3 感谢阅读~ 1 前言 本文用的是 fedora 40 kde plasma 6。 因为有很多的软件都同时…

VTK----VTK数据结构详解1(几何篇)

在讲VTK的数据结构之前&#xff0c;我们先了解可视化数据的两个特征&#xff1a;离散性、有规则或无规则。 离散性。当我们使用计算机去表示我们的数据时&#xff0c;一般都是基于有限数量的点做信息的采样&#xff08;或插值&#xff09;&#xff0c;因此可视化的数据是以一种…

Sylar C++高性能服务器学习记录07 【协程模块-知识储备篇】

早在19年5月就在某站上看到sylar的视频了&#xff0c;一直认为这是一个非常不错的视频&#xff0c;由于本人一直是自学编程&#xff0c;基础不扎实&#xff0c;也没有任何人的督促&#xff0c;没能坚持下去&#xff0c;每每想起倍感惋惜。恰逢互联网寒冬&#xff0c;在家无事&a…

MacOS 文件系统种类及介绍

MacOS 文件系统种类 详细介绍 详细介绍 从图片中我们可以看到一个文件系统选择器的界面&#xff0c;列出了多种不同的文件系统选项。这些文件系统各有其特点和用途&#xff0c;以下是它们之间的主要区别&#xff1a; APFS&#xff1a;Apple File System&#xff0c;是苹果公司为…

Python实现自动化的服务器部署和配置管理库之pyinfra使用详解

概要 在现代软件开发中,自动化部署和配置管理变得越来越重要。Python pyinfra库是一个强大的工具,可以帮助开发者实现自动化的服务器部署和配置管理。本文将介绍pyinfra库的安装、特性、基本功能、高级功能、实际应用场景以及总结。 安装 首先,来看一下如何安装pyinfra库。…

UE4_动画基础_FootIK

角色由于胶囊体的阻挡&#xff0c;双脚与地面平行&#xff0c;不会与斜坡、台阶等贴合&#xff0c;有一条腿会处于悬空状态&#xff0c;通过双骨骼IK节点使一只脚太高&#xff0c;让后胶囊体下降&#xff0c;修正双脚的角度。这就是逆向运动IK的方法。 一、新建第三人称模板游戏…

【并集查找 最大公约数 调和数】952. 按公因数计算最大组件大小

本文涉及知识点 图论 并集查找 最大公约数 调和数 LeetCode952. 按公因数计算最大组件大小 给定一个由不同正整数的组成的非空数组 nums &#xff0c;考虑下面的图&#xff1a; 有 nums.length 个节点&#xff0c;按从 nums[0] 到 nums[nums.length - 1] 标记&#xff1b; 只…

Git的操作和使用

一、基本操作 1、创建git本地仓库 &#xff08;1&#xff09;创建目录&#xff1a;mkdir gitcode &#xff08;2&#xff09;进入目录&#xff1a;cd gitcode/ &#xff08;3&#xff09;查询目录内容&#xff1a;ls &#xff08;4&#xff09;在当前目录下创建git本地仓库…

react引入iconfont的svg图标

react引入iconfont的svg图标 本文目录 react引入iconfont的svg图标普通图标通过link引入css组件内引入css使用 svg图标通过script引入js组件内引入js使用 通过封装组件自定义封装组件中调用 通过antd封装使用 普通图标 通过link引入css <link rel"stylesheet" h…

机器学习进行情感分析(上)

目录 一、 绪论二、 数据处理1. 构建CSV文档2. 构建模型前的思考2.1. 问题2.2. 解决方法 3. 读取数据4. 用正则表达式来进行对特定符号的剔除5. 使用口袋模型进行文本处理和特征提取 三、 数据划分 一、 绪论 近年来&#xff0c;随着互联网和社交媒体的快速发展&#xff0c;人们…

python自动化登录(测试篇)

起初是想抓取下请求看能不能做模拟登录。无奈发现&#xff0c;目标网站的请求数据是加密过的&#xff0c;而且网站代码也是编译后的代码。要从编译后的代码中提取加密算法。我的第一想法是明知不可为而不为。但是转念一想&#xff0c;何不试试python大法。 1.前期准备 python我…

Android图片压缩、Drawable和Bitmap转换、bitmap和base64转换

1. Android图片压缩、Drawable和Bitmap转换、bitmap和base64转换 1.1. Drawable和Bitmap之间的转化 1.1.1. bitmap和Drawable间的区别 Bitmap - 称作位图&#xff0c;一般位图的文件格式后缀为bmp&#xff0c;当然编码器也有很多如RGB565、RGB888。作为一种逐像素的显示对象执…