☰
LeetCode 724:寻找数组的中心下标(前缀和) —— 题解
2026/10/18 6:53:55 网站建设 项目流程

👋 欢迎阅读

🎯 欢迎来到「寻找数组的中心下标」题解之旅!本文将带你从"找出数组左右两侧重量相等的平衡点"这一直观场景出发,深入理解前缀和 + 后缀和的巧妙运用,并掌握如何用两个辅助数组记录左右累加来在 O(n) 内定位中心下标。

在开始之前,建议你先:

  • 了解题目背景:这是 LeetCode 724 题,给定整数数组nums,中心下标定义为左侧所有元素之和等于右侧所有元素之和的位置(两侧都不含该元素本身),返回最左侧的中心下标,不存在返回-1。本质上,问题转化为同时维护每个位置的左右两侧累加和并比较。

  • 明确学习目标:掌握前缀数组 f 与后缀数组 g 的构建,理解f[i]、g[i] 都不包含 nums[i] 本身的语义,并熟练处理首尾下标与单元素数组等边界情况。

  • 准备好环境:建议在本地 IDE 或 LeetCode 在线编辑器中打开代码,边看边运行,亲手验证示例(如nums = [1, 7, 3, 6, 5, 6]输出3)。

本文将从问题转化、左右数组构建、双数组比较、边界防护到代码实现,层层递进。即使你对前缀和还不熟悉,我们也会从"把每个位置左右两侧的账先算好,再逐位核对"这一直觉出发,让你轻松抓住核心思想——左账右账各算一遍,相等处即中心。现在,让我们一起累计两侧之和,找到数组的平衡点吧! ⚖️🎯

🏠个人主页:愿旖旎
📘专栏传送门:算法专栏
💻当前学习内容:前缀和


一.题目

724. 寻找数组的中心下标 - 力扣(LeetCode)

​

二、算法分析

一、问题分析(前置分析)

  • 题目要求:在数组nums中找出中心下标(左侧元素和 == 右侧元素和,均不含自身),返回最左侧的;不存在返回-1。
  • 关键约束:元素可能为负数;中心下标可能是首尾位置(一侧和为 0);要求最左侧的中心。
  • 核心思路:暴力做法对每个位置都重新累加左右两侧,总代价 O(n²);用前缀数组 f(左侧和)与后缀数组 g(右侧和)各预处理一遍,比较即得答案,总复杂度O(n)。

📌 例子:暴力为什么不可行

数组[1, 7, 3, 6, 5, 6],检查下标 3 时需累加左侧1+7+3与右侧5+6;检查下标 4 时又要重新累加1+7+3+6与6——每个位置的左右和都从零开始重算,重复计算大量重叠区间,n 个位置最坏 O(n²)。

二、算法策略(前缀数组 f + 后缀数组 g)

核心步骤:

  1. 初始化:f[0] = 0(下标 0 左侧无元素)、g[n-1] = 0(下标 n-1 右侧无元素)。
  2. 构建前缀 f:f[i] = f[i-1] + nums[i-1],表示下标 i左侧所有元素之和(从左往右)。
  3. 构建后缀 g:g[j] = g[j+1] + nums[j+1],表示下标 j右侧所有元素之和(从右往左)。
  4. 比较定位:从左到右找第一个f[i] == g[i]的位置返回;全不满足返回-1。

📊 示例(nums = [1, 7, 3, 6, 5, 6]):

下标 i012345
nums[i]173656
f[i](左侧和)018111722
g[i](右侧和)2720171160

构建时 f 从左往右逐个累加(f[3] = f[2] + nums[2] = 8 + 3 = 11),g 从右往左递推(g[3] = g[4] + nums[4] = 6 + 5 = 11);比较发现i=3 时 f[3] == g[3] == 11,返回3(左侧1+7+3与右侧5+6均为 11)。

三、正确性说明(简单版本)

  • f、g 语义精确:f[i] = nums[0] + ... + nums[i-1]递推保证恰好是 i 左侧全部元素之和,不含 nums[i];g[i]对称地是右侧全部元素之和,递推无误差。
  • 比较条件等价:中心下标的定义"左侧和 == 右侧和"与f[i] == g[i]逐字对应,等式成立即满足题意,不会错判。
  • 首尾覆盖完整:f[0] = 0、g[n-1] = 0使下标 0 与 n-1 的"空侧"正确表示为 0,中心在边界时也能命中,不漏解。
  • 最左侧保证:从左到右扫描,第一个满足条件的位置即最左侧中心,符合题目要求。

📌 例子:为什么 f[i] 不含 nums[i] 本身

下标 3 处:f[3] = 11来自1+7+3,g[3] = 11来自5+6,元素6(即 nums[3])没有计入任何一侧——中心元素本身不属于左右任何一边,这正是题目的定义;若误把自身算入,比较结果会整体偏移、错失真正的中心。

四、实现细节(边界防护)

  • 初始化:f、g均开n大小;f[0] = 0、g[n-1] = 0(vector 默认也为 0,但语义上必须明确)。
  • 边界防护:构建 f 时i从 1 到n-1,构建 g 时j从n-2到 0,均不越界;n = 1时 f[0] = g[0] = 0,直接返回 0;元素为负时 f、g 可能为负,不影响比较。
  • 复杂度:时间 O(n)(两次构建 + 一次比较),空间 O(n)(两个辅助数组)。
  • 关键操作:f[i] = f[i-1] + nums[i-1](前缀递推)、g[j] = g[j+1] + nums[j+1](后缀递推)、if (f[i] == g[i]) return i;(中心判定)。

📌 例子:单元素数组的边界

nums = [5]:f[0] = 0、g[0] = 0,比较f[0] == g[0]成立,返回0——该元素左右两侧均为空(和为 0),天然是中心;若漏掉 f[0]/g[0] 的初始化,这里会比较到未定义值,结果不确定。

五、返回值(目标映射)

  • 返回第一个满足f[i] == g[i]的i:中心下标;全部不满足返回-1,对应题目"不存在则返回 -1"。

三.代码

class Solution { public: int pivotIndex(vector<int>& nums) { int n = nums.size(); // 1. 初始化两个辅助数组:f 记录左侧和,g 记录右侧和 vector<int> f(n); // f[i] = 下标 i 左侧所有元素之和 vector<int> g(n); // g[i] = 下标 i 右侧所有元素之和 f[0] = 0; // 下标 0 左侧没有元素,和为 0 g[n - 1] = 0; // 下标 n-1 右侧没有元素,和为 0 // 2. 构建前缀数组 f:从左往右累加(不含 nums[i] 自身) for (int i = 1; i < n; i++) { f[i] = f[i - 1] + nums[i - 1]; } // 3. 构建后缀数组 g:从右往左累加(不含 nums[j] 自身) for (int j = n - 2; j >= 0; j--) { g[j] = g[j + 1] + nums[j + 1]; } // 4. 从左到右找第一个左右和相等的位置 for (int i = 0; i < n; i++) { if (f[i] == g[i]) { return i; // 左侧和 == 右侧和,即中心下标 } } // 5. 不存在中心下标 return -1; } };

四、易错点分析

难点1:f[i]、g[i] 的语义——"不含 nums[i] 本身"

f[i] = f[i - 1] + nums[i - 1]; // 加的是 nums[i-1],不是 nums[i] g[j] = g[j + 1] + nums[j + 1]; // 加的是 nums[j+1],不是 nums[j]

f[i] 表示 i左侧的和,所以递推时加的是nums[i-1];g[i] 表示 i右侧的和,加的是nums[j+1]。最容易写错的是下标偏移:若写成f[i] = f[i-1] + nums[i],f[i] 会把自身算进去,所有位置的左右和整体错位,比较结果完全失真。

难点2:两个数组的构建方向相反

for (int i = 1; i < n; i++) // f:从左往右 for (int j = n - 2; j >= 0; j--) // g:从右往左

f 依赖前一个f[i-1],必须正向遍历;g 依赖后一个g[j+1],必须反向遍历。方向写反时,f 会访问未初始化的 f[i-1](越界或取到垃圾值),g 同理——这是两个循环最隐蔽的错误,且编译器不会报错。

难点3:f[0] = 0、g[n-1] = 0 的边界初始化

f[0] = 0; // 最左端:左侧无元素 g[n - 1] = 0; // 最右端:右侧无元素

vector<int>默认初始化为 0,不写这两行也能跑,但语义必须明确:中心下标可能是 0(整个数组左侧为空)或 n-1(右侧为空)。若漏掉初始化并误用其他构造方式(如vector<int> f(n, -1)),首尾位置会永远无法命中中心。

难点4:为什么返回第一个满足的 i 就是"最左侧"

for (int i = 0; i < n; i++) { if (f[i] == g[i]) return i; // 立即返回 }

题目要求"若有多个中心下标,返回最左侧的那个"。从左到右扫描并首次命中即返回,天然满足最左侧要求。若改成"记录最后一个"或"收集全部",会违反题意或改变返回值。

五、流程图

🎯 闭幕

🎉 恭喜你完成了「寻找数组的中心下标」问题的学习!

为了巩固知识并进一步拓展,建议你:

🚀动手实践
在 LeetCode 上提交代码,尝试不同的测试用例。

💡深入思考

  • 本题使用前缀和数组f和后缀和数组g分别记录每个位置左侧和右侧的元素和。为什么f[0] = 0和g[n-1] = 0是合理的?如果中心下标在端点(0 或 n-1),这种初始化如何处理?

  • 构建f数组时,f[i] = f[i-1] + nums[i-1],为什么不包含nums[i]自身?如果包含自身,判定条件需要如何调整?

  • 本题采用了两个辅助数组,空间复杂度为 O(n)。能否只用一个变量(前缀和)配合数组总和来完成判断?如果可以,请描述思路。

  • 如果数组元素包含负数,当前算法是否仍然正确?中心下标的定义是否受影响?

📚延伸挑战

  • 如果要求不借助额外数组,仅使用 O(1) 空间解决本题,请写出核心思路。如果你觉得本文对你有所帮助,欢迎:

👍点赞 / 收藏
👤关注作者,获取更多题解
💬留言交流你的疑问或优化思路


📌深入思考答案

  • f[0]=0和g[n-1]=0是合理的,因为端点左侧或右侧没有元素,总和为 0。若中心下标在端点,只需另一端和也为 0 即可满足条件(例如nums=[1],中心下标为 0)。

  • 不包含自身是因为中心下标的定义要求“左右两侧元素和相等”,不包括自身;若包含自身,则条件变为f[i] + nums[i] == g[i](仍需调整)。

  • 可优化为 O(1) 空间:先计算数组总和total,然后从左向右扫描,维护leftSum(左侧和),右侧和 =total - leftSum - nums[i],比较leftSum == rightSum即可,无需两个数组。

  • 负数不影响,因为判断的是“和相等”,负数只影响数值大小,不改变相等逻辑,算法完全适用。

🔍延伸挑战答案

  • 挑战2:O(1) 空间思路见上方答案:先求总和total,再左扫描维护leftSum,用total - leftSum - nums[i]得到右侧和,比较相等即可。

  • 祝你在算法之路上越走越稳,早日攻克每一道难题!下次见 🚀✨

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询