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²),数据量大时会超时。

前缀和优化(推荐)

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

第一步:从左往右算 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)。额外使用了 leftright 两个数组。


三、代码逐行解读

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;
    }
};

四、进阶优化:空间压缩

上面的代码用了 leftright 两个额外数组。实际上可以只用一个数组,把额外空间从 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) 额外空间
相关推荐
ychqsq1 小时前
45.新芽
经验分享·职场和发展
计算机安禾1 小时前
【数据库系统原理】第4篇:关系数据结构的形式化定义:域、笛卡尔积与关系模式
数据结构·数据库·算法
手写码匠2 小时前
手写 DeepSeek 推理引擎优化:从 FP16 到 INT4 的量化加速实战
人工智能·深度学习·算法·aigc
GuWenyue2 小时前
LeetCode 76 最小覆盖子串|JS 滑动窗口标准解法
前端·算法·面试
一只齐刘海的猫2 小时前
【Leetcode】移动零
算法·leetcode·职场和发展
人道领域2 小时前
【LeetCode刷题日记】131.分割回文串,动态规划优化
java·开发语言·leetcode
落羽的落羽3 小时前
【项目】JsonRpc框架——开发实现1(细节功能、字段定义、抽象层、具象层)
linux·服务器·网络·c++·人工智能·算法·机器学习
handler013 小时前
【算法】并查集(普通/扩展/带权)模板与例题
数据结构·c++·笔记·算法·c·图论·查并集
嵌入式ZYXC3 小时前
第1篇:《面试题:画一个STM32最小系统电路,每个元件的作用》
stm32·单片机·嵌入式硬件·面试·职场和发展