每日一道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;
    }
}
相关推荐
mikuyyds1 小时前
geo-toolbox 水文插件算法解析:从 Muskingum 到 Muskingum-Cunge
算法·rust·gis
Omics Pro1 小时前
斯坦福Nature+Science|广义虚拟细胞基础大模型
数据库·人工智能·算法·机器学习·自然语言处理
代数狂人1 小时前
机器学习数学基础──从零开始 导读
人工智能·算法
CoderYanger1 小时前
A.每日一题:835. 图像重叠
java·开发语言·程序人生·leetcode·面试·职场和发展·学习方法
圣保罗的大教堂2 小时前
leetcode 3524. 求出数组的 X 值 I 中等
leetcode
Zane19942 小时前
暴力字符串匹配失配就要把文本指针往回拉,KMP凭什么能让它一直往前走
算法
Tim_103 小时前
【LeetCode】338、比特位计数
c++·算法·leetcode
木子算法3 小时前
不是重心也不是中点:费马—韦伯点、它的最优性条件与迭代求解
人工智能·算法·目标跟踪
2401_832298104 小时前
人机协同:AI时代全新工作与学习范式
职场和发展
童园管理札记4 小时前
从政策驱动到课堂落地:2026年“人工智能+教育”全景解读与技术实践指南
人工智能·python·深度学习·职场和发展·学习方法