每日一道leetcode(2026.04.23):等值距离和

每日一道leetcode(2026.04.23):等值距离和

  • [1. 题目](#1. 题目)
  • [2. 分析](#2. 分析)
  • [3. 代码实现](#3. 代码实现)

1. 题目

给你一个下标从 0 开始的整数数组 nums 。现有一个长度等于 nums.length 的数组 arr 。对于满足 numsj == numsi 且 j != i 的所有 j ,arri 等于所有 |i - j| 之和。如果不存在这样的 j ,则令 arri 等于 0 。

返回数组 arr 。

示例 1:

输入:nums = 1,3,1,1,2

输出:5,0,3,4,0

解释:

i = 0 ,nums0 == nums2 且 nums0 == nums3 。因此,arr0 = |0 - 2| + |0 - 3| = 5 。

i = 1 ,arr1 = 0 因为不存在值等于 3 的其他下标。

i = 2 ,nums2 == nums0 且 nums2 == nums3 。因此,arr2 = |2 - 0| + |2 - 3| = 3 。

i = 3 ,nums3 == nums0 且 nums3 == nums2 。因此,arr3 = |3 - 0| + |3 - 2| = 4 。

i = 4 ,arr4 = 0 因为不存在值等于 2 的其他下标。

示例 2:

输入:nums = 0,5,3

输出:0,0,0

解释:因为 nums 中的元素互不相同,对于所有 i ,都有 arri = 0 。

提示:

1 <= nums.length <= 10e5

0 <= numsi <= 10e9

2. 分析

这道题是求数组中所有相同元素的距离之和,主要难点在于nums的长度和值的范围是10e5和10e9级别。同样的,先尝试暴力解法,通过一层遍历,将所有相同的元素放到哈希表的数组中,再遍历进行遍历计算所有的距离和。这种解法能通过90%以上的用例。

记得之前有道与之类似的题,也是放哈希表,然后遍历遇到超时,当时的解法是当list长度超过64时,使用双向指针来优化,有不错的效果。然后这道题使用策略明显不适用,因为无论咋地,都得全遍历所有值相同的下标。用例里面有个全是相同的数值,基数有很大,这样层层遍历必超时。

官方解法是通过哈希表分组+前缀和,涉及到一定的公式推导。

我大概花了下面这个图,其实也能快速得出结论。

假设有a到g这7个相同的数值,所有数值到a的距离我们先通过一层遍历计算出来,注意,是使用分组之后的下标列表进行计算,不是原nums来进行全遍历。然后,在计算所有元素到b的距离和时,其实是有规律的,根据箭头的方向,我们将元素左边的距离和暂且称为前缀后,元素右边的距离和称为后缀和,从a移动到b后,前缀和增加了b-a,而后缀和减少了5(b-a)。

继续从b移动到c,前缀和增加了2(c-b),而后缀和减少了4(c-b)。

这样,在有距离a的距离和的基础上,遍历时又能很容易获得b-a的距离,对应的系数,也很容易观察得来,就可以快速计算出同类数值的距离和啦。

3. 代码实现

java 复制代码
class Solution {
    public long[] distance(int[] nums) {
        long[] arr = new long[nums.length];
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (!map.containsKey(nums[i])) {
                map.put(nums[i], new ArrayList<>());
            }
            List<Integer> list = map.get(nums[i]);
            list.add(i);
        }
        for (Map.Entry<Integer, List<Integer>> next : map.entrySet()) {
            List<Integer> list = next.getValue();
            if (list.size() == 1) {
                arr[list.get(0)] = 0;
            }
            // 计算其它下标到第一个下标的距离和
            long dis = 0;
            int first = list.get(0);
            for (int j = 1; j < list.size(); j++) {
                dis += list.get(j) - first;
            }
            // 遍历计算所有通知的距离和
            long preDis = 0;
            long suffixDis = dis;

            int preCount = 0;
            for (int j = 0; j < list.size(); j++) {
                // 当前下标距离前一个下标的距离
                long curDis = 0L;
                if (j > 0) {
                    curDis = list.get(j) - list.get(j - 1);
                }
                preDis += preCount * curDis;
                suffixDis -= curDis * (list.size() - preCount);
                arr[list.get(j)] = preDis + suffixDis;
                preCount++;
            }
        }
        return arr;
    }
}
相关推荐
血色橄榄枝5 小时前
基于用户注册信息的关键词检测挑战赛「Datawhale AI 夏令营」
人工智能·算法·机器学习
c238566 小时前
第二篇:《测试指挥官:可视化单题自测框架(含 assert 实操)》
java·数据库·c++·算法·安全性测试
六点_dn7 小时前
Linux学习笔记-printf命令
linux·运维·算法
遥感知识服务8 小时前
Sentinel-1 + DEM + FwDET + 随机森林:从快速水深初估到多因子误差修正
算法·随机森林·sentinel
来一碗刘肉面8 小时前
顺序表与链表的比较
数据结构·算法·链表
alphaTao8 小时前
LeetCode 每日一题 2026/7/13-2026/7/19
算法·leetcode
nnerddboy8 小时前
脑电信号处理实战 03 | 运动想象脑机接口入门:ERD/ERS、CSP 空间滤波与左右拳想象解码
算法·信号处理
QN1幻化引擎10 小时前
Dalin L — 我造了一门支持中文编程的语言,完整移植到 Rust 了
人工智能·算法·机器学习
Rainy Blue88310 小时前
C转C++速成
c语言·c++·算法
txzrxz10 小时前
二分图详解
数据结构·c++·算法·图论·深度优先搜索·二分图染色