前缀和在计算区间和这类题目时十分方便,因此,在学习算法时应当学习和掌握这种方法。
第一道:
(1)题目
58. 区间和(第九期模拟笔试) (kamacoder.com) (这种题的风格是ACM模式的)
给定一个整数数组 Array,计算该数组在每个指定区间内元素的总和。
输入描述
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。
输出描述
输出每个指定区间内元素的总和。
(2)思路
给定一个大小为n的数组和两个下标,计算两个下标之间的区间和。这题看起来非常的简单。直接遍历下标值,累加返回即可。但是如果两个下标每次都是0和n-1,那是不是每次都要将整个数组累加一次。时间复杂度O(n*m) m为执行次数。时间复杂度并不小。因此,这里采用前缀和进行计算。
前缀和的基本思想就是将数组的区间和存储起来,当使用时直接用大区间和减去小区间和即可。
(3)解题流程
1.定义两个动态数组nums和p。
2.对nums进行赋值操作,同时计算nums的区间和赋给p。例如p[i]表示nums数组从0到i的区间和。
3. 输入要计算的区间(a,b)。如果a==0,直接输出p[b]。如果a!=0,输出p[b]-p[a-1]。
代码实现:
#include<iostream>
using namespace std;
#include<vector>
int main()
{
int n=0,a=0,b=0,sum=0;
cin>>n;
vector<int> nums(n,0);
vector<int> p(n,0);
for(int i=0;i<n;i++)
{
scanf("%d", &nums[i]);
sum+=nums[i];
p[i] = sum;
}
while(~scanf("%d%d", &a, &b))
{
if(a==0) printf("%d\n",p[b]);
else printf("%d\n",p[b]-p[a-1]);
}
return 0;
}
使用cin和cout进行输入输出可能会超时,可以改用scanf和printf。效率更高点。
第二道:
(1)题目
44. 开发商购买土地(第五期模拟笔试) (kamacoder.com)
【题目描述】
在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。
现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。
然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。
为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。
注意:区块不可再分。
【输入描述】
第一行输入两个正整数,代表 n 和 m。
接下来的 n 行,每行输出 m 个正整数。
输出描述
请输出一个整数,代表两个子区域内土地总价值之间的最小差距。
【输入示例】
3 3 1 2 3 2 1 3 1 2 3
【输出示例】
0
(2)思路
这道题依旧是用前缀和的方式进行处理。将一块n*m的土地按横向或纵向进行划分,是两块土地的价值差最小。可以将两种划分方式分别进行计算,得到价值差最小的值,然后返回即可。
以纵向划分为例,创建一个数组p,p[i]表示前 i 列的累加和。找到一个i值,使两部分价值差最小,等价于 p[m-1]-p[i-1]-p[i-1]。p[m-1]-p[i-1]表示i到m-1列的值,p[i-1] 表示0到i-1列的值。相减就是两块区间的价值差。找打最小的返回即可。横向划分的原理一样。
(3)解题流程
1.定义大小为n*m二维数组将输入的值存储起来。
2.定义个大小为m的数组存储列的累加和。
3.定义个大小为n的数组存储行的累加和。
4.遍历列数组,通过计算p[m-1]-p[i-1]-p[i-1]找到最小的价值差。(可能存在负数,取个绝对值)。
5.遍历行数组,通过计算p[m-1]-p[i-1]-p[i-1]找到最小的价值差。
6.返回最小的价值差。
代码实现:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include <climits>
int main()
{
int n,m,minvalue=INT_MAX;
cin>>n>>m;
vector<vector<int>> nums(n,vector<int>(m,0));
//输入数据
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>nums[i][j];
}
}
int sum=0;
//行求和
vector<int> rowSum(n,0);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
sum+=nums[i][j];
}
rowSum[i] = sum;
}
sum=0;
//列求和
vector<int> colSum(m,0);
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
sum+=nums[j][i];
}
colSum[i] = sum;
}
//列分隔
for(int i=1;i<m;i++)
{
int q_value =colSum[m-1]-colSum[i-1];
int value = abs(q_value-colSum[i-1]);
minvalue = min(minvalue,value);
}
//行分割
for(int i=1;i<n;i++)
{
int q_value =rowSum[n-1]-rowSum[i-1];
int value = abs(q_value-rowSum[i-1]);
minvalue = min(minvalue,value);
}
cout<<minvalue<<endl;
return 0;
}