LeetCode 2574. 左右元素和的差值

LeetCode 2574. 左右元素和的差值

一、题目含义

给定一个数组 nums,对于数组中的每个位置 i:

  • 左侧和 leftSum[i] :nums[i] 左边所有元素的和(不包含 nums[i] 本身)
  • 右侧和 rightSum[i] :nums[i] 右边所有元素的和(不包含 nums[i] 本身)

要求返回一个数组 answer,其中 answer[i] = |leftSum[i] - rightSum[i]|。

边界情况

  • i = 0 时,左边没有元素,leftSum[0] = 0
  • i = n-1 时,右边没有元素,rightSum[n-1] = 0

示例

复制代码
输入:nums = [10, 4, 8, 3]

逐步计算:

位置 i numsi 左侧元素 leftSum 右侧元素 rightSum |leftSum - rightSum|
0 10 (无) 0 4, 8, 3 15 |0 - 15| = 15
1 4 10 10 8, 3 11 |10 - 11| = 1
2 8 10, 4 14 3 3 |14 - 3| = 11
3 3 10, 4, 8 22 (无) 0 |22 - 0| = 22
复制代码
输出:[15, 1, 11, 22]

二、解题思路

暴力做法(不推荐)

对每个位置 i,分别向左遍历求和、向右遍历求和。每个位置耗时 O(n),总共 O(n²),数据量大时会超时。

前缀和优化(推荐)

核心观察 :leftSum 和 rightSum 都可以用递推的方式计算,不需要每次从头求和。

第一步:从左往右算 leftSum
复制代码
leftSum[0] = 0                          // 左边没有元素
leftSum[i] = leftSum[i-1] + nums[i-1]   // 在前一个结果上累加

为什么可以这样?因为 leftSum[i-1] 已经是 nums[0] + nums[1] + ... + nums[i-2],现在再加上 nums[i-1],恰好就是 nums[i] 左边所有元素的和。

以示例为例:

复制代码
leftSum[0] = 0
leftSum[1] = 0 + 10 = 10
leftSum[2] = 10 + 4  = 14
leftSum[3] = 14 + 8  = 22
第二步:从右往左算 rightSum
复制代码
rightSum[n-1] = 0                                // 右边没有元素
rightSum[i] = rightSum[i+1] + nums[i+1]          // 在后一个结果上累加

逻辑完全对称,方向相反:

复制代码
rightSum[3] = 0
rightSum[2] = 0 + 3  = 3
rightSum[1] = 3 + 8  = 11
rightSum[0] = 11 + 4 = 15
第三步:求差的绝对值
复制代码
answer[i] = |leftSum[i] - rightSum[i]|

复杂度分析

指标 值
时间复杂度 O(n)
空间复杂度 O(n)

三趟遍历,每趟 O(n),总时间 O(n)。额外使用了 left 和 right 两个数组。


三、代码逐行解读

cpp 复制代码
class Solution {
public:
    vector<int> leftRightDifference(vector<int>& nums) {
        vector<int> ret(nums.size());       // 存放最终答案
        vector<int> left(nums.size()), right(nums.size());  // 左侧和、右侧和

        // 第一步:从左往右,递推计算 leftSum
        for (int i = 0; i < nums.size(); i++) {
            if (i == 0) {
                left[0] = 0;               // 最左边,左侧无元素
            } else {
                left[i] = left[i - 1] + nums[i - 1];  // 递推:前一个左侧和 + 前一个元素
            }
        }

        // 第二步:从右往左,递推计算 rightSum
        for (int i = nums.size() - 1; i >= 0; i--) {
            if (i == nums.size() - 1) {
                right[i] = 0;              // 最右边,右侧无元素
            } else {
                right[i] = right[i + 1] + nums[i + 1];  // 递推:后一个右侧和 + 后一个元素
            }
        }

        // 第三步:计算每个位置的差的绝对值
        for (int i = 0; i < nums.size(); i++) {
            ret[i] = abs(left[i] - right[i]);
        }

        return ret;
    }
};

四、进阶优化:空间压缩

上面的代码用了 left 和 right 两个额外数组。实际上可以只用一个数组,把额外空间从 O(n) 降到 O(1)。

思路:用一个变量代替 rightSum 数组

  1. 先从左往右填好 left 数组
  2. 再从右往左遍历,用一个变量 rightSum 记录右侧累加和,边遍历边算答案
cpp 复制代码
class Solution {
public:
    vector<int> leftRightDifference(vector<int>& nums) {
        int n = nums.size();
        vector<int> left(n);
        // 计算前缀和
        for (int i = 1; i < n; i++) {
            left[i] = left[i - 1] + nums[i - 1];
        }
        // 从右往左,用变量维护 rightSum
        int rightSum = 0;
        for (int i = n - 1; i >= 0; i--) {
            left[i] = abs(left[i] - rightSum);  // 直接在 left 上覆盖为答案
            rightSum += nums[i];                 // 更新右侧和(给下一轮 i-1 用)
        }
        return left;
    }
};

理解要点 :rightSum 初始为 0(最右边元素的右侧和就是 0),每往左走一步,就把当前元素加进去,因为对下一个位置来说,当前元素就是"右侧元素"之一。

复杂度对比

版本 时间 额外空间
基础版本 O(n) O(n)
空间压缩版本 O(n) O(1)*

*不计返回值占用的空间


五、总结

要点 说明
问题本质 求每个位置左右两侧元素和的差的绝对值
核心技巧 前缀和递推,避免重复求和
方向 leftSum 从左往右递推,rightSum 从右往左递推
边界 最左侧 leftSum=0,最右侧 rightSum=0
可优化 用变量代替 rightSum 数组,省掉 O(n) 额外空间
相关推荐
lzhdim3 小时前
AI的分类
人工智能·算法·机器学习·分类·数据挖掘
凤凰院凶涛QAQ6 小时前
《Java版数据结构 & 集合类剖析》Map & Set & 反射:“从哈希碰撞到红黑树转换,反射帮你扒开 HashMap 的桶数组看个究竟”
java·数据结构·算法
w_zero_one8 小时前
算法--模拟
java·数据结构·算法
秋天的怀念_David8 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
lll23526917798 小时前
HR如何快速整理面试沟通内容?
面试·职场和发展
零售校长9 小时前
西湖区零售门店店长面试怎么准备
面试·职场和发展·零售
秋天的怀念_David9 小时前
算法一千零一夜 · 第十四夜 幻方与奇妙的二进制
java·程序人生·算法
薛定e的猫咪9 小时前
(ICLR 2020)MAML 靠的不是快速学习,而是特征复用
人工智能·深度学习·学习·算法·机器学习
薛定e的猫咪9 小时前
(ICLR 2026)DF-META:面向 FJSP 的无导数元学习实例自适应调度
人工智能·深度学习·学习·算法·机器学习
java_nnnn10 小时前
LeetCode刷题滑动窗口(水果成篮+找到字符串中所有字母的异位词)Java
java·开发语言·leetcode