本博文为《代码随想录》学习笔记,原文链接:代码随想录
题目
原题链接:58. 区间和(第九期模拟笔试)
题目描述
给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间下标:a,b (b > = a),直至文件结束。
输出描述
输出每个指定区间内元素的总和。
输入示例
5
1
2
3
4
5
0 1
1 3
输出示例
3
9
提示信息
数据范围:
0 < n <= 100000
题解
方法一:暴力解法
注意**处代码的写法,之前没有这样写过
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,a,b;
cin>>n;
int nums[n];
for(int i=0;i<n;i++)
{
cin>>nums[i];
}
while(cin>>a>>b)//** 注意这里的写法
{
int sum=0;
for(int i=a;i<=b;i++)sum+=nums[i];
cout<<sum<<endl;
}
return 0;
}
vector初始化
这里纠正之前关于vector的一个误区,vector初始化的方式有以下几种
1、定义空向量
vector<int> a; //相当于空数组
2、定义具有10个整型元素的向量
vector<int> a(10); //相当于a[10]
3、定义具有10个整型元素的向量,且赋予每个元素初值为1
vector<int> a(10,1); //相当于a[10] = {1}
4、定义与向量b具有相同值的向量a
vector<int> a(b); //将向量b赋值给向量a,即向量a等于向量b
5、将向量b中下标0-2(共三个)的元素赋值给a
//第一个数据是起始地址,第二个数据是结束地址(不包括),第二个数据就是你要截取的长度加1
vector<int> a(b.begin(), b.begin()+3);6、从数组中获得初值
int b[7] = {1,2,3,4,5,6,7}; //定义整形数组
vector<int> a(b, b+7); //将数组b赋值给a,第一个数据是起始地址,第二个数据是结束地址(不包括)
7、二维数组初始化
vector<vector<int>> a; //初始化为int型二维数组,相当于int a[][]
下标只能获取已存在的元素,所以以下赋值方法对第一种初始化方法是错误的
for(int i=0; i<10; i++){
a[i] = i; //应使用a.push_back(i)
}
但当数组中已经存在元素则可以使用上述方法进行赋值,因此方法一还可以写成如下形式:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
for (int i = 0; i < n; i++) cin >> vec[i];
while (cin >> a >> b) {
int sum = 0;
// 累加区间 a 到 b 的和
for (int i = a; i <= b; i++) sum += vec[i];
cout << sum << endl;
}
}
提交代码,发现超时了
当查询范围和查询次数较大时,这种暴力解法的时间复杂度时非常大的。
方法二:前缀和方法
对前缀和的思路进行举例说明,例如我们要统计vec[i]这个数组上的区间和。
我们先做累加,即p[i]表示下标0到i的vec[i]累加之和。如图:
如果,我们想统计,在vec数组上 下标 2 到下标 5 之间的累加和,那就用 p[5] - p[1] 就可以了。
p[1] = vec[0] + vec[1];
p[5] = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];
p[5] - p[1] = vec[2] + vec[3] + vec[4] + vec[5];
p[5] - p[1]
就是 红色部分的区间和。
而 p 数组是我们之前就计算好的累加和,所以后面每次求区间和的之后 我们只需要 O(1) 的操作。
特别注意: 在使用前缀和求解的时候,要特别注意 求解区间。
如上图,如果我们要求 区间下标 [2, 5] 的区间和,那么应该是 p[5] - p[1],而不是 p[5] - p[2]。在解题时可以通过画图来帮助理解。
编写代码如下:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,a,b;
cin>>n;
int nums[n];
int p[n];//前缀和数组
for(int i=0;i<n;i++)
{
cin>>nums[i];
p[i]=p[i-1]+nums[i];
}
while(cin>>a>>b)
{
int sum=p[b]-p[a-1];
cout<<sum<<endl;
}
return 0;
}
《代码随想录》中给出的代码如下:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
vector<int> p(n);
int presum = 0;
for (int i = 0; i < n; i++) {
cin >> vec[i];
presum += vec[i];
p[i] = presum;
}
while (cin >> a >> b) {
int sum;
if (a == 0) sum = p[b];
else sum = p[b] - p[a - 1];
cout << sum << endl;
}
}
C++ 代码 面对大量数据 读取 输出操作,最好用scanf 和 printf,耗时会小很多:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
vector<int> p(n);
int presum = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &vec[i]);
presum += vec[i];
p[i] = presum;
}
while (~scanf("%d%d", &a, &b)) {
int sum;
if (a == 0) sum = p[b];
else sum = p[b] - p[a - 1];
printf("%d\n", sum);
}
}