题解:学而思编程 中心位置
【题目来源】
学而思编程:中心位置
【题目描述】
给定一个包含 \(n\) 个元素的数组 \(A={a_1,a_2,\ldots,a_n}\),数组的中心位置如下定义:
中心位置是数组的一个下标 \(k\)(\(1\le k \le n\)),其左侧的所有元素之和 \(sum_l=a_1+a_2+ \ldots+a_{k-1}\) 等于右侧的所有元素之和 \(sum_r=a_{k+1} + a_{k+2}+\ldots+a_n\)。特别的 \(k=1\) 时 \(sum_l = 0\);\(k=n\) 时 \(sum_r=0\)。
请你找到数组 \(A\) 的中心位置,如果有多个中心位置,输出最靠近左边的一个即可,如果不存在中心位置,输出 \(-1\)。
【输入】
第一行一个整数 \(n\);
第二行 \(n\) 整数 \(a_1, a_2, \ldots, a_n\)。
【输出】
一行一个整数,表示数组 \(A\) 的中心位置。
【输入样例】
3
1 2 3
【输出样例】
-1
【核心思想】
-
问题分析:给定长度为 \(n\) 的数组 \(a_1, a_2, \ldots, a_n\),寻找中心位置 \(k\) 使得左侧元素之和等于右侧元素之和,即 \(\sum_{i=1}^{k-1} a_i = \sum_{i=k+1}^{n} a_i\)。若有多个输出最左边的,不存在则输出 \(-1\)。这是一个前缀和 + 线性扫描问题,关键在于利用前缀和快速计算左右两侧的和。
-
算法选择:
- 前缀和预处理:
s[i] = a_1 + a_2 + \ldots + a_i,实现 \(O(1)\) 区间求和 - 线性扫描枚举:遍历每个位置 \(k\),用前缀和计算左右两侧和并比较
- 前缀和预处理:
-
关键步骤:
- 初始化:读取 \(n\)(数组长度)和数组 \(a[1..n]\)
- 计算前缀和:
s[0] = 0- 遍历 \(i\) 从 \(1\) 到 \(n\):
s[i] = s[i-1] + a[i]
- 枚举中心位置:
- 遍历 \(k\) 从 \(1\) 到 \(n\):
suml = s[k-1]:左侧元素之和 \(a_1 + \ldots + a_{k-1}\)sumr = s[n] - s[k]:右侧元素之和 \(a_{k+1} + \ldots + a_n\)- 若
suml == sumr:输出 \(k\) 并结束程序(最左边的中心位置)
- 遍历 \(k\) 从 \(1\) 到 \(n\):
- 若遍历结束未找到:输出 \(-1\)
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),前缀和计算 \(O(n)\),扫描枚举 \(O(n)\)
- 空间复杂度:\(O(n)\),前缀和数组
s[0..n]
-
前缀和的核心思想:
- 区间求和降维:前缀和
s[i]存储前 \(i\) 项的累计和,任意区间 \([l, r]\) 的和可通过s[r] - s[l-1]在 \(O(1)\) 内计算 - 边界统一处理:\(k = 1\) 时
suml = s[0] = 0,\(k = n\) 时sumr = s[n] - s[n] = 0,无需特殊判断 - 贪心最早满足:从左到右扫描,第一个满足条件的位置即为最左边的中心位置,找到后立即返回
- 等价变形:条件 \(\sum_{i=1}^{k-1} a_i = \sum_{i=k+1}^{n} a_i\) 等价于 \(2 \times s[k-1] + a_k = s[n]\),也可用于判断
- 适用于"寻找平衡点/分割点"类问题,前缀和将 \(O(n)\) 的左右求和优化为 \(O(1)\),线性扫描即可解决
- 区间求和降维:前缀和
【算法标签】
模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, a[100010], s[100010];
int main()
{
cin >> n; // 输入数组长度
for (int i = 1; i <= n; i++)
{
cin >> a[i]; // 输入数组元素
s[i] = s[i - 1] + a[i]; // 计算前缀和
}
// 遍历每个位置k,检查它是否是平衡点
for (int k = 1; k <= n; k++)
{
int suml = s[k - 1]; // 左边元素的和:a[1]到a[k-1]
int sumr = s[n] - s[k]; // 右边元素的和:a[k+1]到a[n]
if (suml == sumr) // 如果左右两边和相等
{
cout << k << endl; // 输出平衡点位置
return 0; // 找到第一个就返回
}
}
cout << -1 << endl; // 没有找到平衡点
return 0;
}
【运行结果】
3
1 2 3
-1
浙公网安备 33010602011771号