LeetCode 2615 等值距离和:前缀和优化O(n)解法深度解析

前言

在LeetCode算法题库中,2615. 等值距离和是一道中等难度的数组经典题 ,核心考察哈希表分组+前缀和优化 的解题思想。题目看似可以用暴力枚举解决,但面对10^5的大数据量,暴力解法会直接超时。本文将从题目解析、暴力解法缺陷、前缀和优化思路、代码详解、复杂度分析五个维度,深度拆解这道题的最优解法。

一、题目详细解析

1. 题目描述

给定一个下标从 0 开始的整数数组 nums,构造一个等长数组 arr

  • 对于每个下标 iarr[i] 等于所有满足 nums[j] == nums[i] 且 j != i 的下标 ji 的绝对差之和 |i-j|

  • 若没有相同值的其他下标,arr[i] = 0

2. 示例说明

输入:nums = [1,3,1,1,2] 输出:[5,0,3,4,0]

  • 下标0:值为1,相同值下标为2、3 → |0-2| + |0-3| = 5

  • 下标1:值为3,无相同值 → 0

  • 下标2:值为1,相同值下标为0、3 → |2-0| + |2-3| = 3

3. 核心约束

  • 数组长度 1 <= nums.length <= 10^5(大数据量,必须线性复杂度)

  • 元素值范围 0 <= nums[i] <= 10^9(需用哈希表存储)

二、暴力解法:思路与缺陷

1. 暴力思路

最直观的想法:遍历每个下标 i,再遍历整个数组找到所有与 nums[i] 相等的下标 j,累加绝对差。

2. 代码伪码

复制代码
vector<long long> distance(vector<int>& nums) {
    int n = nums.size();
    vector<long long> ans(n, 0);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (i != j && nums[i] == nums[j]) {
                ans[i] += abs(i - j);
            }
        }
    }
    return ans;
}

3. 致命缺陷

时间复杂度为 **O(n²)**,当 n=10^5 时,运算量达到 10^10,远超算法时间限制,直接超时。因此必须优化。

三、优化核心:前缀和+哈希表分组

题目提示明确给出了优化方向:前缀和,我们分两步实现优化:

步骤1:哈希表分组

相同数值的下标才需要计算绝对差,因此用哈希表对数组分组:

  • Key:数组中的数值

  • Value:该数值对应的所有下标集合(有序数组)

例如示例 [1,3,1,1,2],分组结果: 1: [0,2,3]3: [1]2: [4]

步骤2:前缀和公式推导(核心)

对于一组相同数值的下标数组 pos = [p0, p1, p2, ..., pk-1],我们需要计算每个 pos[i] 与组内其他元素的绝对差之和。

设:

  • 组内元素个数:k

  • 当前下标:pos[i]

  • 前缀和:preSum[i] = pos[0] + pos[1] + ... + pos[i]

  • 组内总下标和:totalSum = preSum[k-1]

公式拆分
  1. 左侧元素和pos[i] 左侧有 i 个元素 [p0, p1, ..., pi-1] 绝对差和 = i * pos[i] - preSum[i-1]

  2. 右侧元素和pos[i] 右侧有 k-i-1 个元素 [pi+1, ..., pk-1] 绝对差和 = (totalSum - preSum[i]) - (k-i-1) * pos[i]

  3. 总绝对差和:左侧和 + 右侧和

这个公式将O(k)的遍历计算 降为O(1)的数学计算,是线性复杂度的关键!

四、最优解法代码逐行解析

以下是题目对应的C++最优代码,我们逐行拆解:

复制代码
class Solution {
public:
    vector<long long> distance(vector<int>& nums) {
        int n = nums.size();
        // 答案数组:必须用long long,避免int溢出
        vector<long long> ans(n, 0);
        // 哈希表:key=数值,value=对应下标集合
        std::unordered_map<int, std::vector<int>> hashMap;
        
        // 第一步:遍历数组,完成下标分组
        for (int i = 0; i < n; i++) {
            hashMap[nums[i]].push_back(i);
        }

        // 第二步:遍历每个分组,用前缀和计算答案
        for (const auto& pair : hashMap) {
            // 分组内的下标数组
            const auto& pos = pair.second;
            int k = pos.size();
            // 计算分组内所有下标的总和
            long long totalSum = 0;
            for (int idx : pos) {
                totalSum += idx;
            }

            // 前缀和:动态更新,无需额外数组
            long long prefixSum = 0;
            for (int i = 0; i < k; ++i) {
                long long cur = pos[i];
                // 计算左侧绝对差和
                long long leftSum = (long long)i * cur - prefixSum;
                // 计算右侧绝对差和
                long long rightSum = (totalSum - prefixSum - cur) - (long long)(k - i - 1) * cur;
                // 赋值到答案数组的对应下标位置
                ans[cur] = leftSum + rightSum;
                // 更新前缀和
                prefixSum += cur;
            }
        }
        return ans;
    }
};

关键细节说明

  1. 数据类型 :答案必须用long long!因为10^5个下标相乘会超出int范围,强制类型转换(long long)避免溢出;

  2. 动态前缀和 :无需单独开辟前缀和数组,用变量prefixSum动态累加,节省空间;

  3. 哈希表遍历:只处理有多个下标的分组,单个下标的分组直接跳过(答案默认为0)。

五、复杂度分析

1. 时间复杂度:O(n)

  • 分组遍历:O(n),每个下标仅入组一次;

  • 前缀和计算:O(n),所有分组的元素总数等于原数组长度;

  • 总复杂度:线性级别,完美适配10^5的大数据量。

2. 空间复杂度:O(n)

  • 哈希表存储所有下标,空间占用为O(n);

  • 答案数组为O(n),属于必要空间。

五、总结

这道题是前缀和在数组问题中的经典应用,核心解题思路可以总结为三点:

  1. 分组思想:用哈希表将相同数值的下标聚合,排除无关元素;

  2. 数学优化:通过前缀和公式将绝对差和的计算从O(k)降为O(1);

  3. 细节规避 :大数据量下必须使用long long避免整型溢出。

掌握这种「分组+前缀和」的思路,还可以解决LeetCode上同类的下标距离和问题,是算法面试中的高频考点~

相关推荐
生成论实验室2 小时前
生成态势猜想:一种统一的宇宙动力学语法
人工智能·科技·神经网络·算法·信息与通信
旖-旎2 小时前
深搜(二叉树的所有路径)(6)
c++·算法·leetcode·深度优先·递归
啦啦啦_99992 小时前
3. KNN算法之 常用的距离度量方式(欧式&曼哈顿&切比雪夫&闵式距离)
算法
朝风工作室3 小时前
实时全景拼接|支持任意路数输入,8*8K RTX3050 实测 10ms 内
图像处理·算法·计算机视觉
nianniannnn3 小时前
HNU计算机系统期中题库详解(五)位运算与逻辑运算
算法·位运算·计算机系统
徐新帅4 小时前
4181:【GESP2603七级】拆分
c++·学习·算法·信奥赛
黎梨梨梨_4 小时前
C++入门基础(下)(重载,引用,inline,nullptr)
开发语言·c++·算法
Jasmine_llq4 小时前
《B4411 [GESP202509 二级] 优美的数字》
算法·暴力枚举算法·逐位校验算法·统一数位判断算法·条件计数算法·自定义函数判断算法
做时间的朋友。4 小时前
小华地图寻宝
算法