题解:学而思编程 中心位置

【题目来源】

学而思编程:中心位置

【题目描述】

给定一个包含 \(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

【核心思想】

  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\)。这是一个前缀和 + 线性扫描问题,关键在于利用前缀和快速计算左右两侧的和。

  2. 算法选择

    • 前缀和预处理s[i] = a_1 + a_2 + \ldots + a_i,实现 \(O(1)\) 区间求和
    • 线性扫描枚举:遍历每个位置 \(k\),用前缀和计算左右两侧和并比较
  3. 关键步骤

    • 初始化:读取 \(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\) 并结束程序(最左边的中心位置)
    • 若遍历结束未找到:输出 \(-1\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\),前缀和计算 \(O(n)\),扫描枚举 \(O(n)\)
    • 空间复杂度:\(O(n)\),前缀和数组 s[0..n]
  5. 前缀和的核心思想

    • 区间求和降维:前缀和 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
posted @ 2026-07-04 14:53  团爸讲算法  阅读(4)  评论(0)    收藏  举报